Авторынок Казахстана¶

Автор: Кирин Павел.¶

Telegram: @meat_murder¶

На входе имеются данные о положении дел авторынка Казахстана за период с января по сентябрь 2019 года.
Описание полей датасета:

  • Год – год продажи (2019)
  • Месяц – месяц продажи (январь - сентябрь)
  • Компания – название автоцентра
  • Бренд – название продаваемой марки автомобиля
  • Модель – название модели автомобиля
  • Модификация – модификация модели автомобиля
  • Год выпуска – год производства автомобиля
  • Страна-производитель – страна, где произведен автомобиль
  • Вид топлива – бензин, дизель, электричество, гибрид
  • Объём двиг л – объем двигателя автомобиля в литрах
  • Коробка передач – тип коробки переключения передач
  • Тип привода – в итоге оставляем RWD – задний привод, FWD – передний привод, 4WD – полный привод, 2WD – все остальное
  • Сегмент – сегмент, к которому относится авто
  • Регион – регион продажи
  • Наименование дилерского центра – название центра
  • Тип клиента – юридическое или физическое лицо
  • Форма расчета – наличный и безналичный расчет
  • Количество – количество автомобилей в заказе
  • Цена USD – цена автомобиля
  • Продажа USD – цена заказа (цена авто умноженная на количество и за вычетом скидок если есть)
  • Область – область продажи
  • Сегментация 2013 – сегмент автомобиля
  • Класс 2013 – класс автомобиля
  • Сегментация Eng – английская сегментация
  • Локализация производства – где произведен автомобиль

Постановленные задачи:

  • Полная предобработка датасета с максимально возможным сохранением данных.

Общий исследовательский анализ данных:

  • Продажи по брендам, сегментам коммерческого и некоммерческого авто
  • Модели-лидеры на рынке
  • Продажи по регионам
  • Продажи автоцентров

Анализ продаж Mercur Auto:

  • Выручка: общая, по маркам, средняя, ежемесячная, ежемесячная по маркам
  • Продажи по регионам: общие, по маркам
  • BCG анализ

Выводы и рекомендации на основании общего анализа и анализа Mercur Auto.


In [1]:
#Для работы с данными
import pandas as pd
import numpy as np
import sweetviz as sv

#Для графиков
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

#Снятие ограничений
import warnings
warnings.filterwarnings("ignore")
pd.set_option("display.max_columns", None)

#Для скачивания датасета
from IPython.display import FileLink

#Здесь живут настройки тем графиков
sns.set_style('darkgrid')
plt.style.use('ggplot')

#Эт список цветовых решений для плотли
#print(plt.style.available)
In [2]:
# Чтобы не возникло сложностей с запуском, я добавлю здесь команды для установки библиотек на машину с которой будет запущена тетрадь.

# Прежде всего необходимо открыть терминал (либо выполнить в самой ячейке), и запустить следующие команды:

#   Sweet-Viz можно установить этой командой:
#   $ pip install sweetviz

#   Для установки FileLink:
#   !pip install ipyfilechooser
In [3]:
#Функция для вывода информации о датасете
def inform(df):
    display(df.head()) # вывод первых 5 строк таблицы
    df.info() # получение информации
    print()
    print ('Количество дубликатов:', df.duplicated().sum())
    print()
    print ('Число пропусков:\n', df.isna().sum())
    print()
    print ('Доля пропусков:\n', df.isna().mean()*100,1)
    return df

Предобработка данных¶

Первый взгляд на датасет¶

In [4]:
#Переменная с локальным путём к файлу. При запуске с другой машины заменить путь на местный :)
patch = 'C:/Users/79990/Desktop/auto_kz/df/'
In [5]:
#Выгрузка информации о датасете
auto = pd.read_csv(patch + 'auto_kz.csv', sep=';')
auto = inform(auto)
Год Месяц Компания Бренд Модель Модификация Год выпуска Страна-производитель Вид топлива Объём двиг, л, Коробка передач Тип привода Сегмент Регион Наименование дилерского центра Тип клиента Форма расчета Количество Цена, USD Продажа, USD Область Сегментация 2013 Класс 2013 Сегментация Eng Локализация производства
0 2019 Май Mercur Auto Audi A3 TFSI 2018 Германия Бензин 1,4 S-tronic передний Легковые автомобили Premium Алматы Mercur Auto Алматы Физ. Лицо безналичный 1.0 28115 28115 г.Алматы Легковые автомобили C класс C Импорт
1 2019 Август Mercur Auto Audi A3 TFSI 2018 Германия Бензин 1,4 S-tronic передний Легковые автомобили Premium Алматы Mercur Auto Алматы Юр. Лицо наличный 1.0 32246,99 32246,99 г.Алматы Легковые автомобили C класс C Импорт
2 2019 Апрель Mercur Auto Audi A4 TFSI 2018 Германия Бензин 1,4 S-Tronic FWD Легковые автомобили Premium Алматы Mercur Auto Алматы Физ. Лицо безналичный 1.0 32000 32000 г.Алматы Легковые автомобили D класс D Импорт
3 2019 Июль Mercur Auto Audi A4 TFSI 2018 Германия Бензин 1,4 S-tronic передний Легковые автомобили Premium Алматы Mercur Auto Алматы Юр. Лицо безналичный 1.0 31929 31929 г.Алматы Легковые автомобили D класс D Импорт
4 2019 Июль Mercur Auto Audi A4 TFSI 2018 Германия Бензин 1,4 S-tronic передний Легковые автомобили Premium Алматы Mercur Auto Алматы Физ. Лицо наличный 1.0 31929 31929 г.Алматы Легковые автомобили D класс D Импорт
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 39966 entries, 0 to 39965
Data columns (total 25 columns):
 #   Column                          Non-Null Count  Dtype  
---  ------                          --------------  -----  
 0   Год                             39966 non-null  int64  
 1   Месяц                           39966 non-null  object 
 2   Компания                        39966 non-null  object 
 3   Бренд                           39966 non-null  object 
 4   Модель                          39966 non-null  object 
 5   Модификация                     36375 non-null  object 
 6   Год выпуска                     39465 non-null  object 
 7   Страна-производитель            39966 non-null  object 
 8   Вид топлива                     36826 non-null  object 
 9   Объём двиг, л,                  35708 non-null  object 
 10  Коробка передач                 36711 non-null  object 
 11  Тип привода                     35677 non-null  object 
 12  Сегмент                         33205 non-null  object 
 13  Регион                          39966 non-null  object 
 14  Наименование дилерского центра  39966 non-null  object 
 15  Тип клиента                     32919 non-null  object 
 16  Форма расчета                   14038 non-null  object 
 17  Количество                      39960 non-null  float64
 18  Цена, USD                       39966 non-null  object 
 19  Продажа, USD                    39966 non-null  object 
 20  Область                         39966 non-null  object 
 21  Сегментация 2013                39966 non-null  object 
 22  Класс 2013                      39966 non-null  object 
 23  Сегментация Eng                 39966 non-null  object 
 24  Локализация производства        39966 non-null  object 
dtypes: float64(1), int64(1), object(23)
memory usage: 7.6+ MB

Количество дубликатов: 18698

Число пропусков:
 Год                                   0
Месяц                                 0
Компания                              0
Бренд                                 0
Модель                                0
Модификация                        3591
Год выпуска                         501
Страна-производитель                  0
Вид топлива                        3140
Объём двиг, л,                     4258
Коробка передач                    3255
Тип привода                        4289
Сегмент                            6761
Регион                                0
Наименование дилерского центра        0
Тип клиента                        7047
Форма расчета                     25928
Количество                            6
Цена, USD                             0
Продажа, USD                          0
Область                               0
Сегментация 2013                      0
Класс 2013                            0
Сегментация Eng                       0
Локализация производства              0
dtype: int64

Доля пропусков:
 Год                                0.000000
Месяц                              0.000000
Компания                           0.000000
Бренд                              0.000000
Модель                             0.000000
Модификация                        8.985137
Год выпуска                        1.253566
Страна-производитель               0.000000
Вид топлива                        7.856678
Объём двиг, л,                    10.654056
Коробка передач                    8.144423
Тип привода                       10.731622
Сегмент                           16.916879
Регион                             0.000000
Наименование дилерского центра     0.000000
Тип клиента                       17.632488
Форма расчета                     64.875144
Количество                         0.015013
Цена, USD                          0.000000
Продажа, USD                       0.000000
Область                            0.000000
Сегментация 2013                   0.000000
Класс 2013                         0.000000
Сегментация Eng                    0.000000
Локализация производства           0.000000
dtype: float64 1
In [6]:
#Данный способ развертывает в браузере html дашборд с полной информацией о данных которые мы скармливаем библиотеке sweetviz
#При необходимости открыть дашборд и просмотреть данные - убрать # со строки my_report.show_html()
my_report = sv.analyze(auto)
#my_report.show_html()

Предварительно наблюдаем несоответсвие типов данных, множество дубликатов, достаточно большое количество пропусков. И это только начало :) Согласовав с заказчиком, избавлюсь от полей которые дублируют информацию и будут мешать анализу данных.

Наличие такого большого количества дубликатов (почти половина датасета, 18 698 из 39 966 строк) обосновано тем, что при сборе данных отсутствует уникальная идентификафия строк. Удалять я их пока не стану, т.к. удаление в дальнейшем может исказить анализ этих данных, и к тому же на крайний случай удалить дубли никогда не поздно.

Данные нуждаются в тщательном изучении и устранении всех ошибок, коих здесь весьма не мало.

P.S. Развернув дополнительно дашборд с визуализацией данных мной было замечено внушительное количество неявных дубликатов, с чем буду разбираться по ходу проведения предобработки.

Удаление лишних столбцов¶

Избавляю датасет от лишнего.

In [7]:
#Удаляю то что дублируется либо не имеет отношения к дальнейшему анализу
auto = auto.drop(columns=['Модификация', 'Сегмент', 'Наименование дилерского центра', 'Форма расчета', 'Сегментация Eng', 'Локализация производства'])
In [8]:
#Переименую столбцы в человеческий вид
auto = auto.rename(columns={'Сегментация 2013': 'Сегментация', 'Класс 2013': 'Класс', 'Объём двиг, л,': 'Объем двигателя', 'Страна-производитель': 'Производитель',
                            'Продажа, USD': 'Продажа USD', 'Цена, USD': 'Цена USD'})

#Теперь все названия приведу к snake case, с ними будет удобнее работать.
auto.columns = auto.columns.str.lower().str.replace(' ', '_')

#Глянем на преображение
auto.head()
Out[8]:
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
0 2019 Май Mercur Auto Audi A3 2018 Германия Бензин 1,4 S-tronic передний Алматы Физ. Лицо 1.0 28115 28115 г.Алматы Легковые автомобили C класс
1 2019 Август Mercur Auto Audi A3 2018 Германия Бензин 1,4 S-tronic передний Алматы Юр. Лицо 1.0 32246,99 32246,99 г.Алматы Легковые автомобили C класс
2 2019 Апрель Mercur Auto Audi A4 2018 Германия Бензин 1,4 S-Tronic FWD Алматы Физ. Лицо 1.0 32000 32000 г.Алматы Легковые автомобили D класс
3 2019 Июль Mercur Auto Audi A4 2018 Германия Бензин 1,4 S-tronic передний Алматы Юр. Лицо 1.0 31929 31929 г.Алматы Легковые автомобили D класс
4 2019 Июль Mercur Auto Audi A4 2018 Германия Бензин 1,4 S-tronic передний Алматы Физ. Лицо 1.0 31929 31929 г.Алматы Легковые автомобили D класс

Датасет очищен от ненужных полей, теперь работать с ним чуть комфортнее. Перейдем к этапу изменения типов данных.

Приведение столбцов к нужному типу данных¶

Все столбцы имеющие информацию с целочисленными значениями, и числам с плавающей точкой необходимо привести к другим типам данных (int и float соответственно), для дальнейшей возможности работать с ними. Для начала я выведу уникальные значения каждого столбца по отдельности чтобы понимать какие ошибки закрались при записи, исправлю их, а затем выполню замену типа данных. Таким образом мы сэкономим время увидев сразу какие неявные дубликаты прячутся в массиве данных, и приведем их к рабочему состоянию.

In [9]:
#Вывод уникальных значений столбцов которые нас интересуют
print('Уникальные значения столбца "Количество":', auto['количество'].unique())
print()
print('Уникальные значения столбца "Год выпуска":', auto['год_выпуска'].unique())
print()
print('Уникальные значения столбца "Объем двигателя":', auto['объем_двигателя'].unique())
Уникальные значения столбца "Количество": [  1.   2.   4.   3.   7.   5.   8.  10.   6.   9.  11.  19.  12.  70.
  29.  18.  37.  17.  15.  24.  14.  13.  25.  63.  23.  30.  21.  60.
  nan  22.  16.  35.  28.  32.  54. 115.  46.  33.  47.  20.  66.  27.
  50.  36.  26.  31.  34.  40.  43.  51.  42.  38.  41. 100.  -1.  79.
  62.]

Уникальные значения столбца "Год выпуска": ['2018' '2017' '2019' nan '2016' '2014' '2013' '2011' '2\xa0018'
 '2\xa0019']

Уникальные значения столбца "Объем двигателя": ['1,4' '2' '3' '4,4' '6,6' '1,5' '1,596' '2,4' '1,7' '26,7' '25,7' '24,7'
 '23,7' '22,7' '21,7' '20,7' '19,7' '18,7' '17,7' '16,7' '15,7' '14,7'
 '13,7' '12,7' '11,7' '10,7' '9,7' '8,7' '7,7' '6,7' '5,7' '4,7' '3,7'
 '2,7' '6,2' '1,4 Turbo' '2,5' '1,6' nan '2,8' '4,3' '4,3,' '1,6 MPI'
 '2,0 MPI' '2,4 GDI' '2,4 MPI' '2,5 CRDI VGT' '2,5 CRDI WGT' '3,9' '7,5'
 '12,3' '1,6 T-GDI' '2,0 CRDI' '2.0' '3,5' '5,6' '5,2' '3,0 L' '1.6' '1.5'
 '5' '1,598' '1,248' '1,998' '2,359' '1,999' '3,342' '1,591' '3,47' '1,69'
 '1,774' '2.5' '2.7 ' '3.5' '2.7' '4.6' '4,6' '5.7' '1,8' '10,5' '4' '5,5'
 '12' '12,8' '11' '2,2' '1,2' '1,485' 'MT' 'AT' '0' '13' '1,33' '#Н/Д'
 '4.0' '2.4G' '2,4G' '2.8' '2,693' '2,0' '3,8' '3.8' '1,2T' '3,6' '7,6'
 '4,9' '2.0h' '2,9' '400 Л.С.' '4,98 L,' '4,98' '88 KWH' '8,4 L,' '6,7L'
 '6,5']

Выведя уникальные значения наблюдается следующая картина: В столбце с количеством есть значения NaN и их следует заменить заглушкой 0, потому что в противном случае не получится изменить тип данных. Отрицательное значение -1 полагаю что является возвратом, или же сбой при записи данных. Тоже заменить заглушкой 0. В уникальных значениях года выпуска наблюдаются некорректные записи года, полагаю что это связано с ошибкой при конвертации данных из екселя в .csv, их я верну в нормальный вид, а пропущенные значения NaN я удалю, т.к. их 1.25% во всем датасете, а значит отсутствие их на анализ никак не повлияет.

В столбце с объемом двигателя творится ад! Здесь следует все привести в единому стандарту, заполнить пустые значения (надо подумать чем и как). Я наблюдаю типы двигателя вместо объема (методом поиска в интернете соответсвия объема этим типам можно заполнить значения), значение с лошадинными силами думаю так же можно вывести на экран отдельно и понять к каким авто это относится, а после этого заменить значения на объем двигателя согласно характеристикам в интернете.

Так же есть столбцы с продажей и ценой в долларах, где иногда встречаются запятые вместо точек. Это связано с человеческим фактором при записи данных сотрудниками, форма заполнения допускает и точку и запятую как правильный символ при записи, потому и имеем отсутствие единого стандарта. Исправлю заменой запятых на точки, ведь запятая используется в качестве разделителя тысяч, а это не является стандартным форматом для преобразования в float.

In [10]:
#Поставлю заглушку 0 для пропущенных значений в количестве, изменю тип данных
auto['количество'].fillna(0, inplace=True)
auto['количество'] = auto['количество'].replace(-1, 0)
auto['количество'] = auto['количество'].astype(int)

#Удаление пропусков года выпуска (их менее 1% во всем датасете, ничего не потеряем)
auto.dropna(subset=['год_выпуска'], inplace=True)
auto['год_выпуска'] = auto['год_выпуска'].replace({'2\xa0018': '2018', '2\xa0019': '2019'}) #Ставим адекватный номер года
auto['год_выпуска'] = auto['год_выпуска'].astype(int)

#Меняю запятые появившиеся при корявой записи стоимости на точки (иначе заменить тип данных не получится), и меняю типы данных
auto['продажа_usd'] = auto['продажа_usd'].str.replace(',', '.').astype(float)
auto['цена_usd'] = auto['цена_usd'].str.replace(',', '.').astype(float)

Теперь отдельно разберемся с объемом двигателя...

In [11]:
#Начну с простого. Выведу на экран значения авто у которых указаны лошадинные силы, прогуглю, и заменю на верные
engine = auto[auto['объем_двигателя'] == '400 Л.С.']
engine
Out[11]:
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
39544 2019 Февраль Almaty Motors Premium Jaguar I-Pace 2019 UK Электро 400 Л.С. РЕДУКТОР 4WD Алматы Физ. Лицо 1 117236.9729 117236.9729 г.Алматы Внедорожники Компактные SUV
39545 2019 Апрель Almaty Motors Premium Jaguar I-Pace 2019 UK Электро 400 Л.С. РЕДУКТОР 4WD Алматы Физ. Лицо 1 105388.7924 105388.7924 г.Алматы Внедорожники Компактные SUV
39546 2019 Июнь Almaty Motors Premium Jaguar I-Pace 2019 UK Электро 400 Л.С. РЕДУКТОР 4WD Алматы Юр. Лицо 1 120413.2793 120413.2793 г.Алматы Внедорожники Компактные SUV

По скольку все три электромобили - классифицировать объем двигателя в литрах будет не корректно. Потому проставлю значение 0 для Ягуаров.

Теперь разберем что значат буквенные обозначения попавшие в объем двигателя. Путем сёрфинга информации в интернете вот что мне удалось найти:

  • МТ и АТ - механическая и автоматическая трансмиссия, это съехавшие значения (вероятно при выгрузке данных с БД), которые необходимо переместить в столбец коробки передач.
  • 88 KWH - обозначение относящееся к электрокару. Так же как и с предыдущими - не корректно указывать объем, а потому следует заменить эти значения на 0.
  • #Н/Д - обозначение отсутсвия данных. Возможно это связано с ошибкой при выгрузке данных с базы, а может быть это связано с человеческим фактором. Выведя на экран информацию с таким заполнением можно будет найти в интернете характеристики и заполнить их вручную.

Что касается остальных значений - оставим один символ после запятой, тем самым приведем значения к единому стандарту и удалим лишние подписи которые нас не интересуют, и не будут играть роли при анализе.

In [12]:
#Перемещение съехавших значений на свое место.
#Создаем датасет без сдвинутых ячеек
unchanged = auto.query("объем_двигателя not in ['MT', 'AT']")

# датасет со сдвинутыми значениями
to_change = auto.query("объем_двигателя in ['MT', 'AT']")
In [13]:
# чистим датасет от сдвига ячеек
to_change['тип_привода'] = to_change['объем_двигателя']
to_change['объем_двигателя'] = to_change['вид_топлива']
to_change['вид_топлива'] = np.NaN
In [14]:
# сливаем датасеты обратно
auto = pd.concat([to_change, unchanged])

# проверяем корректность слияния
auto.shape
Out[14]:
(39465, 19)
In [15]:
#Точно так же выводим на экран информацию авто с указанием буквенных обозначений/отсутствующих в поле объема двигаетля
engine = auto[(auto['объем_двигателя'] == '#Н/Д') | (auto['объем_двигателя'] == '88 KWH')]
engine
Out[15]:
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
31148 2019 Февраль Toyota Motor Kazakhstan Toyota Corolla 2019 Турция Бензин #Н/Д #Н/Д #Н/Д Нур-Султан Физ. Лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
31149 2019 Февраль Toyota Motor Kazakhstan Toyota Corolla 2019 Турция Бензин #Н/Д #Н/Д #Н/Д Нур-Султан Физ. Лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
32670 2019 Апрель Toyota Motor Kazakhstan Toyota HILUX DC 2019 Таиланд Бензин #Н/Д #Н/Д #Н/Д Алматы Юр. Лицо 1 30870.28194 30870.28194 г.Алматы Пикапы Pick-ups
33070 2019 Июль Toyota Motor Kazakhstan Toyota HILUX DC 2019 Таиланд Бензин #Н/Д #Н/Д #Н/Д Атырау Физ. Лицо 1 27012.45730 27012.45730 Атырауская область Пикапы Pick-ups
39818 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39819 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39820 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39821 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39822 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39823 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39824 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39825 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39826 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы
39827 2019 Июль Allur Auto ANKAI HFF6124G03EV3 2019 Республика Казахстан Электричество 88 KWH NaN 2WD Костанай Юр. Лицо 1 307986.36330 307986.36330 Костанайская область Коммерческие автомобили Большие автобусы

Выведя информацию с марками авто где отсутствуют объема двигателя, наблюдаем картину того что данных нет так же и в столбцах с коробкой передач и типом привода. Ситуация исправимая, вручную укажем нужные параметры взяв их с интернета. Так же в таблицу попалось множество дублей одной модели электро автобуса ANKAI, у которого помимо некорректно указанного объема двигателя еще отсутствует тип коробки передач. Опять же, исправимо внесением данных вручную.

P.S. Полазив на авто.ру, я увидел что короллы 19го года (относящиеся к 12 поколению) имеют несколько вариаций исполнения. Укажу значечния которые чаще встречаются на рынке, а именно: передний привод, механическая кп, и средний объем двигателя - 1.6 литра. Для электро автобуса кпп автомат, объем двигателя меняем на ноль. Для HILUX DC объем 2.8, автомат, 4WD.

In [16]:
#Пропущенные значения для короллы и анкая
#Пропуски для бренда Toyota и моделей Corolla и HILUX DC
toyota_corolla = (auto['бренд'] == 'Toyota') & (auto['модель'] == 'Corolla')
auto.loc[toyota_corolla, ['объем_двигателя', 'коробка_передач', 'тип_привода']] = auto.loc[toyota_corolla, ['объем_двигателя', 'коробка_передач', 'тип_привода']
                                                                                           ].fillna(value={'объем_двигателя': 1.6, 'коробка_передач': 'МТ', 'тип_привода': 'FWD'})

toyota_hilux = (auto['бренд'] == 'Toyota') & (auto['модель'] == 'HILUX DC')
auto.loc[toyota_hilux, ['объем_двигателя', 'коробка_передач', 'тип_привода']] = auto.loc[toyota_hilux, ['объем_двигателя', 'коробка_передач', 'тип_привода']
                                                                                           ].fillna(value={'объем_двигателя': 2.8, 'коробка_передач': 'АТ', 'тип_привода': '4WD'})
#Пропуски для бренда ANKAI
ankai = (auto['бренд'] == 'ANKAI') & (auto['модель'] == 'HFF6124G03EV3')
auto.loc[ankai, ['объем_двигателя', 'коробка_передач']] = auto.loc[ankai, ['объем_двигателя', 'коробка_передач']
                                                                   ].fillna(value={'объем_двигателя': 0, 'коробка_передач': 'АТ'})
In [17]:
#Проверка связи
auto['объем_двигателя'].unique()
Out[17]:
array(['2', '1,6', '1,4', '3', '4,4', '6,6', '1,5', '1,596', '2,4', '1,7',
       '26,7', '25,7', '24,7', '23,7', '22,7', '21,7', '20,7', '19,7',
       '18,7', '17,7', '16,7', '15,7', '14,7', '13,7', '12,7', '11,7',
       '10,7', '9,7', '8,7', '7,7', '6,7', '5,7', '4,7', '3,7', '2,7',
       '6,2', '1,4 Turbo', '2,5', nan, '2,8', '4,3', '4,3,', '1,6 MPI',
       '2,0 MPI', '2,4 GDI', '2,4 MPI', '2,5 CRDI VGT', '2,5 CRDI WGT',
       '3,9', '7,5', '12,3', '1,6 T-GDI', '2,0 CRDI', '2.0', '3,5', '5,6',
       '5,2', '3,0 L', '1.6', '1.5', '5', '1,598', '1,248', '1,998',
       '2,359', '1,999', '3,342', '1,591', '3,47', '1,69', '1,774', '2.5',
       '2.7 ', '3.5', '2.7', '4.6', '4,6', '5.7', '1,8', '10,5', '4',
       '5,5', '12', '12,8', '11', '2,2', '1,2', '1,485', '0', '13',
       '1,33', '#Н/Д', '4.0', '2.4G', '2,4G', '2.8', '2,693', '2,0',
       '3,8', '3.8', '1,2T', '3,6', '7,6', '4,9', '2.0h', '2,9',
       '400 Л.С.', '4,98 L,', '4,98', '88 KWH', '8,4 L,', '6,7L', '6,5'],
      dtype=object)
In [18]:
#функция для удаления лишних символов из объема двигателя
def engine_cleaner(cell):
    if isinstance(cell, int):
        cell = str(cell)
    
    good_symbols = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.'] # список символов, которые мы оставляем
    new_cell = '' # новая пустая строка куда мы будем добавлять "хорошие" символы

    for element in cell:
        if element in good_symbols:
            new_cell += element

    if new_cell.endswith('.'): # отдельно обработаем момент где в конце остается точка
        new_cell = new_cell[:-1]
    
    return new_cell
In [19]:
#Для корректной работы функции приведем столбец к типу строка
auto['объем_двигателя'] = auto['объем_двигателя'].astype('str')

#Как и в предыдущем случае, меняем запятые на точки
auto['объем_двигателя'] = auto['объем_двигателя'].str.replace(',', '.')

#Замена значения электрокаров на ноль
auto['объем_двигателя'] = auto['объем_двигателя'].replace('400 Л.С.', 0)
auto['объем_двигателя'] = auto['объем_двигателя'].replace('88 KWH', 0)
In [20]:
#Применяем функцию
auto['объем_двигателя'] = auto['объем_двигателя'].apply(engine_cleaner)
In [21]:
#Проверка связи
auto['объем_двигателя'].unique()
Out[21]:
array(['2', '1.6', '1.4', '3', '4.4', '6.6', '1.5', '1.596', '2.4', '1.7',
       '26.7', '25.7', '24.7', '23.7', '22.7', '21.7', '20.7', '19.7',
       '18.7', '17.7', '16.7', '15.7', '14.7', '13.7', '12.7', '11.7',
       '10.7', '9.7', '8.7', '7.7', '6.7', '5.7', '4.7', '3.7', '2.7',
       '6.2', '2.5', '', '2.8', '4.3', '2.0', '3.9', '7.5', '12.3', '3.5',
       '5.6', '5.2', '3.0', '5', '1.598', '1.248', '1.998', '2.359',
       '1.999', '3.342', '1.591', '3.47', '1.69', '1.774', '4.6', '1.8',
       '10.5', '4', '5.5', '12', '12.8', '11', '2.2', '1.2', '1.485', '0',
       '13', '1.33', '4.0', '2.693', '3.8', '3.6', '7.6', '4.9', '2.9',
       '4.98', '8.4', '6.5'], dtype=object)
In [22]:
auto.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39465 entries, 23723 to 39965
Data columns (total 19 columns):
 #   Column           Non-Null Count  Dtype  
---  ------           --------------  -----  
 0   год              39465 non-null  int64  
 1   месяц            39465 non-null  object 
 2   компания         39465 non-null  object 
 3   бренд            39465 non-null  object 
 4   модель           39465 non-null  object 
 5   год_выпуска      39465 non-null  int32  
 6   производитель    39465 non-null  object 
 7   вид_топлива      36710 non-null  object 
 8   объем_двигателя  39465 non-null  object 
 9   коробка_передач  36453 non-null  object 
 10  тип_привода      35605 non-null  object 
 11  регион           39465 non-null  object 
 12  тип_клиента      32829 non-null  object 
 13  количество       39465 non-null  int32  
 14  цена_usd         39465 non-null  float64
 15  продажа_usd      39465 non-null  float64
 16  область          39465 non-null  object 
 17  сегментация      39465 non-null  object 
 18  класс            39465 non-null  object 
dtypes: float64(2), int32(2), int64(1), object(14)
memory usage: 5.7+ MB

Столбцы приведены к нужным типам данных, удалены лишние символы, исправлены ошибки возникшие при записи/конвертации данных, неверные значения заменены на правильные.

Проверка столбцов на наличие неявных дублей¶

Теперь, когда числа приведены в порядок, самое время поработать с остальными столбцами. Прежде всего выведу уникальные значения для остальных, и уже будет понятно что с этим делать дальше.

In [23]:
#Функция, которой передается датафрейм и столбцы для вывода уникальных значений.
#Не придется писать лапками код.
def values(dataframe, columns, values_per_line=15): #values_per_line ограничивает строку на 15 значений (чтобы не устали глаза листать)
    for column in columns:
        unique_values = dataframe[column].unique()  #Здесь собираются уникальные значения столбца
        print(f"\033[1mУникальные значения столбца '{column}':\033[0m") # escape-код ANSI, f строка выделяется жирным шрифтом.
        
        for i in range(0, len(unique_values), values_per_line): #Цикл переносящий значения на новую строку, если хи число превышает 15
            values_subset = unique_values[i:i+values_per_line]
            print(', '.join(map(str, values_subset)))

        print()  #Пустая строка между выводами, для комфортного отображения информации
In [24]:
#Вывод значений
values(auto, ['месяц', 'компания', 'бренд', 'модель', 'производитель', 'вид_топлива', 'коробка_передач',
               'тип_привода', 'регион', 'тип_клиента', 'область', 'сегментация', 'класс']
               )
Уникальные значения столбца 'месяц':
Январь, Май, Август, Апрель, Июль, Февраль, Июнь, Сентябрь, Март

Уникальные значения столбца 'компания':
Renault Россия, Mercur Auto, Автоцентр-Бавария, БИПЭК АВТО, Вираж, Eurasia Motor Premium, Daewoo Bus Kazakhstan, Caspian Motors, Каспиан Моторс, СемАЗ, Astana Motors, Astana Motors , Hyundai Com Trans Kazakhstan , Nissan Manufacturing RUS, СВС-ТРАНС
Allur Auto, Almaty Motors Premium, TERRA MOTORS, ТК КАМАЗ, Toyota Motor Kazakhstan, Лифан Моторс Рус, MAN Truck & Bus Kazakhstan, Автомир ГК, Autokapital, Автокапитал, ММС Рус, MMC RUS, Mercur Autos, УзАвто-Казахстан, Равон Моторс Казахстан
Ravon Motors Kazakstan, Scania Central Asia, Subaru Kazakhstan, Volkswagen Group Rus, Автодом Motors KST, Автомир-Центр, ТОО "Eurasia Motor Zhaik", Scandinavian Motors, Хино Моторс Казахстан, Hino Motors 

Уникальные значения столбца 'бренд':
Renault, Audi, BMW, Chevrolet, Daewoo, Ford, Foton, GAZ, Hyundai, Hyundai Truck & Bus, Infiniti, Isuzu, Iveco, Jac, Jaguar
KAMAZ, Kia, Lada, Land Rover, Lexus, Lifan, MAN, Mazda, Mercedes-Benz, Mercedes-Benz Trucks, Mini, Mitsubishi, Nissan, Peugeot, Porsche
Ravon, Scania, Skoda, Subaru, Toyota, UAZ, Volkswagen, Volvo, Урал, Cadillac, Shacman, Hino, Dong Feng, ANKAI, Nefaz
Yutong

Уникальные значения столбца 'модель':
Duster, Sandero, A3, A4, A6, A7, A8, Q5, Q7, 3 серия, 5 серия, 6 серия, 7 серия, X1, X3
X4, X5, X6, X7, Z4, Aveo, Captiva, Niva, Tahoe, Tracker, BS 106 A, Fiesta, Mondeo, BJ3253DMPKB-AD, 2217
2310, 2705, 2752, 3221, 3302, 3308, 3309, Next, Accent, Creta, Elantra, Santa Fe, Sonata, TQ-1/H-1, County
H350, HD 170, HD 65, HD 78, Universe, Tucson, Q50, QX50, QX60, QX80, D-MAX, NMR, NPR, Daily, Daily A
Daily V, Stralis, Tipper, S3, S5, F-Pace, F-Type, XE, XF, XJ, 4308, 4311, 43118, 43253, 43502
44108, 45142, 45143, 53215, 53504, 53605, 54115, 5490, 65111, 65115, 65116, 65117, 6520, 65206, 65225
66052, 6606, Cerato, Optima, Picanto, Quoris, Rio, Sorento, Soul, Sportage, 4x4, Granta, Kalina, Largus, Vesta
XRAY, ВИС, Discovery, Discovery Sport, Range Rover, Range Rover Evoque, Range Rover Sport, ES, GX, LS, LX, NX, RX, RXH, Murman
Solano, X50, X60, TG, 6, CX-5, A-Class, C-Class, CLA-Class, CLS-Class, E-Class, G-Class, GLA-Class, GLC-Class, GLE-Class
GLS-Class, S-Class, Actros, Sprinter, Tourismo, V-Class, Vito, Countryman, ASX, Outlander, Pajero IV, Pajero Sport, Almera, Juke, Murano
Qashqai, Terrano, X-Trail, 301, Partner Panel Van, 911 Carrera S, Cayenne, Macan, Panamera, Nexia R3, R4, Kaptur, Koleos, Logan, Master
G-Series, P-Series, R-Series, Octavia, Rapid, Superb, Forester, Legacy, Outback, XV, Camry, Corolla, HIGHLANDER, HILUX DC, LC Prado
LC200, RAV4, 2206, 3151, 3303, 3741, 3909, 3962, Cargo, Patriot, Patriot Pickup, Amarok, Caddy Kasten , Caddy Maxi Kombi, Caravelle
Jetta, Multivan, Polo, Tiguan, Touareg, Transporter, Transporter Kasten, XC90, 4320, 4320-1951-40, 4320-1951-60, 5557, MYWAY, CX-9, HD 35
Range Rover Velar, BS 106 D, Kodiaq, Escalade, GLC Coupe, X200, E-PACE, Dokker, Eclipse Cross, X70, N120, N75, T6, SX3258DR384, iev
S-Series, NQR, X2, S90, XC60, C-HR, 300, XC40, N56, XT5, 500, Stinger, Hatch, Traverse, NMS85
BJ1069VDJEA-F1, HD 79, BWC6665GA5, i8, UX, 8 серия, Cabrio, HF-D105, NPS, Q8, RS5, Teramont, 5299, I-Pace, S7
45141, 32551, BC 211 MA, EX8, BC 095, Camaro, HFF6850G, Transporter Kombi , GLE Coupe, HFF6124G03EV3, HFF6127GZ-4, Setra, ZK6108HGH, Arkana, V90
58815Z

Уникальные значения столбца 'производитель':
Российская Федерация, Германия, США, Австрия, Республика Казахстан, Корея, Япония, Таиланд, Китай, UK, Узбекистан, Венгрия, Турция, Испания, Нидерланды
Польша, Швеция, Белоруссия, Бельгия

Уникальные значения столбца 'вид_топлива':
nan, Бензин, Дизель, дизель , бензин , гибрид, 1,6, 0, Электро, Электричество

Уникальные значения столбца 'коробка_передач':
4WD, Передний, S-tronic, S-Tronic, Tiptronic, АКПП, АКП, Steptronic, AT, 6 АТ, 5 МТ, 6АТ, MT, 8AT, 5МТ
Powershift S6, 6AT, nan, Мех., 6 AT, 6 MT, 6MT, 5 AT, 5AT, МКПП, 7 DCT, 7DCT, 8 AT, МТ, CVT
DCT, 4 АТ, 6 МТ, 6МТ, 4АТ, 4AT, 8АТ, 8 АТ, 5MT, AMT, CVT (вариатор), CVT (вариATор), CVT(вAриATор), 7G-TRONIC, 9G-TRONIC
12AT, 12АТ, 5АТ, 7АТ, 7AT, 6M/T, PDK, 8-ступ АКПП, 8, 8АКПП, 8 АКПП Tiptronic S, 7 АКПП (PDK), 7 АКПП PDK, 8 АКПП (PDK), АТ
АT, МT, 0, 7 DSG, 7DSG, 6 DSG, 6DSG, #Н/Д, DSG, 6A, 6А, 5M, A/T, M/T, МКП
5М, М/T,  7 АКП, 7АКП, А/T, 8A, TDI, 9AT, РЕДУКТОР

Уникальные значения столбца 'тип_привода':
MT, AT, передний, FWD, quattro, Задний, Полный, AWD, Передний, 4WD, 4х2.2, nan, RWD, 2 WD, 2WD
4 WD, 4X4, 4х4, 4x4, 4x2, 4х2, 4X2, Астана, Передний (FF), 0, FF, #Н/Д, полный, 4Motion

Уникальные значения столбца 'регион':
Уральск, Нур-Султан, Кызылорда, Караганда, Усть-Каменогорск, Шымкент, Алматы, Костанай, Петропавловск, Павлодар, Семей, Актау, Атырау, Актобе, Кокшетау
Рудный, Тараз, Туркестан, Талдыкорган, ЭКСПОРТ, Кульсары, Каскелен, Экибастуз, Риддер, Сарыагаш, Зыряновск

Уникальные значения столбца 'тип_клиента':
nan, Физ. Лицо, Юр. Лицо, Юр.Лицо, физ.лицо, юридическое, физическое, ФизЛицо, ЮрЛицо, Корп. клиент

Уникальные значения столбца 'область':
Западно-Казахстанская область, г.Нур-Султан, Кызылординская область, Карагандинская область, Восточно-Казахстанская область, Южно-Казахстанская область, г.Алматы, Костанайская область, Северо-Казахстанская область, Павлодарская область, Мангистауская область, Атырауская область, Актюбинская область, Акмолинская область, Жамбылская область
Туркестанская область, Алматинская область, Экспорт область

Уникальные значения столбца 'сегментация':
Внедорожники, Легковые автомобили, Коммерческие автомобили, Минивэны, Пикапы

Уникальные значения столбца 'класс':
Субкомпактные SUV, B класс, C класс, D класс, E класс, F класс, Среднеразмерные SUV, Полноразмерные SUV, Спортивные автомобили, Компактные SUV, Большие автобусы, Крупнотоннажные грузовики, Микроавтобусы, Малотоннажные грузовики, Среднетоннажные грузовики
Полноразмерный Минивэн, Средние автобусы, Pick-ups, Развозные автомобили, A класс, Компактвэн

После изучения значений в остальных столбцах можно отметить следующие моменты:

  • 'компания'- Видно что присутствуют неявные дубли, некоторые компании повторяются на русской и английской раскладке. Объединить названия исключив путаницу.

  • 'модель'- Ну.... По скольку здесь большое множество моделей и бегло осматривая их я не могу разглядеть неявные дубли (если они конечно тут есть), допущу вариант того что это адекватные названия/номера моделей которые имеются в серии выпуска авто разных производителей. Пока ничего делать с этим столбцом не буду, на первый взгляд все нормально.

  • 'производитель'- Все названия стран выглядят адекватно, кроме UK. Заменить на Англию.

  • 'вид_топлива'- Вижу пропуски, посмотрим что это (возможно сказались съехавшие значения), закрались значения объема двигателя - следует переместить на место, для оптимизации веса датасета и скорости его обработки машиной предлагаю сделать буквенные обозначения вместо подписей:

    • Э - Электричество
    • Б - Бензин
    • Г - Гибрид
    • Д - Дизель
  • 'коробка_передач'- Полный фарш. Никакой стандартизации ввода данных, с этим придется поработать разделив значения на автомат (АТ), механику(МТ) и роботов (RT). В нашем случае точность в типе коробки передач никак не скажется на качестве анализа этих данных.

  • 'тип_привода'- Снова съехавшие значения механики и автомата со столбца коробки передач. Вернуть на место. Опять же, с целью оптимизации предлагаю все типы привода оформить следующим образом:

    • RWD - Задний привод
    • FWD - Передний привод
    • 4WD - Полный привод
    • AWD - Автоматически подключаемый полный привод
  • 'тип_клиента'- Пропуски заполнить на физ лицо если автомобилей куплено не больше двух. Юр лица приобретают как правило больше трех авто. Значения привести к единой форме.

  • 'класс'- Смущает только Pick-ups. Переименовать на Пикап.

Что касаемо не перечисленных столбцов (месяц, бренд, регион, область, сегментация) - при беглом осмотре с ними все в порядке. Приступаем к исправлению грехов в датасете!

In [25]:
#Переименовываю английские значения в столбцах производитель и класс
auto['производитель'] = auto['производитель'].replace({'UK': 'Англия'})
auto['класс'] = auto['класс'].replace({'Pick-ups': 'Пикап'})
In [26]:
#Исправление неявных дублей в столбце компания.
#Приведем все значения к нижнему регистру и уберем лишние пробелы
auto['компания'] = auto['компания'].str.lower().str.strip()

#Вывод значений
auto['компания'].unique()
Out[26]:
array(['renault россия', 'mercur auto', 'автоцентр-бавария', 'бипэк авто',
       'вираж', 'eurasia motor premium', 'daewoo bus kazakhstan',
       'caspian motors', 'каспиан моторс', 'семаз', 'astana motors',
       'hyundai com trans kazakhstan', 'nissan manufacturing rus',
       'свс-транс', 'allur auto', 'almaty motors premium', 'terra motors',
       'тк камаз', 'toyota motor kazakhstan', 'лифан моторс рус',
       'man truck & bus kazakhstan', 'автомир гк', 'autokapital',
       'автокапитал', 'ммс рус', 'mmc rus', 'mercur autos',
       'узавто-казахстан', 'равон моторс казахстан',
       'ravon motors kazakstan', 'scania central asia',
       'subaru kazakhstan', 'volkswagen group rus', 'автодом motors kst',
       'автомир-центр', 'тоо "eurasia motor zhaik"',
       'scandinavian motors', 'хино моторс казахстан', 'hino motors'],
      dtype=object)
In [27]:
#Теперь одинаковые названия на разных языках
auto['компания'] = auto['компания'].replace({'каспиан моторс': 'caspian motors', 'равон моторс казахстан': 'ravon motors kazakstan',
                                             'хино моторс казахстан': 'hino motors', 'ммс рус': 'mmc rus', 'mercur autos': 'mercur auto',
                                             'автокапитал': 'autokapital'})

auto['компания'].unique()
Out[27]:
array(['renault россия', 'mercur auto', 'автоцентр-бавария', 'бипэк авто',
       'вираж', 'eurasia motor premium', 'daewoo bus kazakhstan',
       'caspian motors', 'семаз', 'astana motors',
       'hyundai com trans kazakhstan', 'nissan manufacturing rus',
       'свс-транс', 'allur auto', 'almaty motors premium', 'terra motors',
       'тк камаз', 'toyota motor kazakhstan', 'лифан моторс рус',
       'man truck & bus kazakhstan', 'автомир гк', 'autokapital',
       'mmc rus', 'узавто-казахстан', 'ravon motors kazakstan',
       'scania central asia', 'subaru kazakhstan', 'volkswagen group rus',
       'автодом motors kst', 'автомир-центр', 'тоо "eurasia motor zhaik"',
       'scandinavian motors', 'hino motors'], dtype=object)

Ну теперь вроде красота :) производитель, класс и компания исправлены.

In [28]:
#Теперь разберемся с типом клиента
#Приведем все значения к нижнему регистру и уберем лишние пробелы
auto['тип_клиента'] = auto['тип_клиента'].str.lower().str.strip()

auto['тип_клиента'].unique()
Out[28]:
array([nan, 'физ. лицо', 'юр. лицо', 'юр.лицо', 'физ.лицо', 'юридическое',
       'физическое', 'физлицо', 'юрлицо', 'корп. клиент'], dtype=object)
In [29]:
#Убираем лишнее
auto['тип_клиента'] = auto['тип_клиента'].replace({'юр.лицо': 'юр. лицо', 'физ.лицо': 'физ. лицо', 'юридическое': 'юр. лицо', 'физическое': 'физ. лицо',
                                                   'физлицо': 'физ. лицо', 'юрлицо': 'юр. лицо'})

auto['тип_клиента'].unique()
Out[29]:
array([nan, 'физ. лицо', 'юр. лицо', 'корп. клиент'], dtype=object)

Несколько слов о отличии юр. лица от корпоративного клиента.

  • Юридическое лицо - это организация, которая имеет право на совершение действий в соответствии с законодательством, включая заключение контрактов, приобретение и продажу имущества, и так далее.

  • Корпоративный клиент - это термин, который обычно используется для обозначения клиента, который является юридическим лицом (как крупным, так и мелким предприятием), и который приобретает продукцию или услуги компании. Однако, корпоративный клиент не обязательно должен быть юридическим лицом. Например, в некоторых случаях, крупные индивидуальные клиенты могут быть классифицированы как корпоративные клиенты.

Таким образом, хотя все корпоративные клиенты могут быть юридическими лицами, не все юридические лица являются корпоративными клиентами. Кроме того, некоторые корпоративные клиенты могут быть индивидуальными клиентами.

In [30]:
#Узнаем сколько значений не имеет указанного типа клиента.
print('Количество пропусков в столбце тип клиента:', auto['тип_клиента'].isna().sum())
Количество пропусков в столбце тип клиента: 6636

Согласовав этот момент с заказчиком, решили заполнить пропуски значениями физ или юр лица в следующих случаях: если совершена одна или две покупки - указываем физическое лицо. Все что больше двух является юридическими, т.к. это чаще всего закупка коммерческих предприятий.

In [31]:
#Функция заполняющая пропуски.
def client_type(row):
    if pd.isna(row['тип_клиента']):
        if row['количество'] >= 2:
            return 'физ. лицо'
        else:
            return 'юр. лицо'
    else:
        return row['тип_клиента']

#Применение функции
auto['тип_клиента'] = auto.apply(client_type, axis=1)

#Проверка
print('Количество пропусков в столбце тип клиента:', auto['тип_клиента'].isna().sum())
auto['тип_клиента'].unique()
Количество пропусков в столбце тип клиента: 0
Out[31]:
array(['юр. лицо', 'физ. лицо', 'корп. клиент'], dtype=object)

Все хорошо, пропуски заполнены, корпоративные клиенты остались на месте, идем дальше.

In [32]:
#Заменим запянутю, т.к. объем двигателя у нас уже отформатирован
auto['вид_топлива'] = auto['вид_топлива'].str.replace(',', '.')

#Найдем строки, где 'тип_топлива' содержит значения '1.6' и '0'
wrong_values = auto[(auto['вид_топлива'] == '1.6') | (auto['вид_топлива'] == '0')]

#Заменим их в столбце 'объем_двигателя'
auto.loc[wrong_values.index, 'объем_двигателя'] = wrong_values['вид_топлива']

#Заменим их в столбце 'тип_топлива' на NaN
auto.loc[wrong_values.index, 'вид_топлива'] = np.nan

#Проверим что получилось
auto['вид_топлива'].unique()
Out[32]:
array([nan, 'Бензин', 'Дизель', 'дизель ', 'бензин ', 'гибрид', 'Электро',
       'Электричество'], dtype=object)
In [33]:
#Функция для замены значений
def map_fuel_type(value):
    if isinstance(value, str):  #Проверяем, является ли значение строкой
        value = value.strip().lower()  #Убираем пробелы и приводим к нижнему регистру
        if value == 'бензин':
            return 'Б'
        elif value == 'дизель' or value == 'дизель ':
            return 'Д'
        elif value == 'электричество' or value == 'электро':
            return 'Э'
        elif value == 'гибрид':
            return 'Г'
    return value  #Возвращаем исходное значение, если не нашли соответствие или если значение не является строкой

#Применим, помянем
auto['вид_топлива'] = auto['вид_топлива'].apply(map_fuel_type)
In [34]:
#Проверим что получилось
auto['вид_топлива'].unique()
Out[34]:
array([nan, 'Б', 'Д', 'Г', 'Э'], dtype=object)
In [35]:
#Датасет, где только строки с пропущенным значением
not_fuel = auto[auto['вид_топлива'].isna()]

print('Количество пропущенных зачений:', auto['вид_топлива'].isna().sum())
Количество пропущенных зачений: 2761

Предлагаю вывести уникальные значения бренда и модели каждого авто, и заполнить пропущенные значения типом топлива характерым для этих авто согласно информации в интернете. Это даст нам относительно точные данные которыми можно заполнить пропуски коих не мало.

In [36]:
#Группировка по бренду и объединение строк с уникальными моделями
brand_model = not_fuel.groupby('бренд')['модель'].unique().reset_index()

#Преобразование списков моделей в строки
brand_model['модель'] = brand_model['модель'].apply(lambda x: ', '.join(x))

brand_model
Out[36]:
бренд модель
0 ANKAI HF-D105, HFF6850G
1 Dong Feng BWC6665GA5
2 Foton BJ3253DMPKB-AD, BJ1069VDJEA-F1
3 GAZ 2310, 2705, 2752, 3221, 3302, 3308, Next
4 Hyundai Truck & Bus HD 65, HD 78, Universe, HD 35, EX8
5 Iveco Daily, Daily A, Daily V, Stralis, Tipper
6 Jac S3, S5, N120, N75, T6, N56
7 Jaguar I-Pace
8 Lada ВИС
9 MAN TG
10 Mazda 6, CX-5, CX-9
11 Peugeot 301, Partner Panel Van
12 Renault Duster, Sandero, Kaptur, Koleos, Logan, Master...
13 Shacman SX3258DR384
14 UAZ 3151, 3741, Cargo, Patriot Pickup
15 Урал 4320, 4320-1951-40, 4320-1951-60, 5557, 32551

На выходе имеем не так много моделей авто в которых есть пробелы данных, а значит вполне реально их заполнить самостоятельно поискав информацию в интернете. Чем я и займусь.

In [37]:
#Ну что ж... Создам словарь с соответствиями моделей и типов топлива
fuel_type = {'HF-D105': 'Б', 'HFF6850G': 'Б', 'BWC6665GA5': 'Б', 'BJ3253DMPKB-AD': 'Б', 'BJ1069VDJEA-F1': 'Б', '2310': 'Б', '2705': 'Б', '2752': 'Б', '3221': 'Б',
                     '3302': 'Б', '3308': 'Б', 'Next': 'Б', 'HD 65': 'Д', 'HD 78': 'Д', 'Universe': 'Д', 'HD 35': 'Д', 'EX8': 'Д', 'Daily': 'Д', 'Daily A': 'Д', 'Daily V': 'Д',
                     'Stralis': 'Д', 'Tipper': 'Д', 'S3': 'Б', 'S5': 'Б', 'N120': 'Б', 'N75': 'Б', 'T6': 'Б', 'N56': 'Б', 'I-Pace': 'Э', 'ВИС': 'Б', 'TG': 'Д', '6': 'Б', 'CX-5': 'Б',
                     'CX-9': 'Б', '301': 'Б', 'Partner Panel Van': 'Б', 'Duster': 'Б', 'Sandero': 'Б', 'Kaptur': 'Б', 'Koleos': 'Б', 'Logan': 'Б', 'Master': 'Д', 'Dokker': 'Б',
                     'Arkana': 'Б', 'SX3258DR384': 'Д', '3151': 'Б', '3741': 'Б', 'Cargo': 'Б', 'Patriot Pickup': 'Б', '4320': 'Д', '4320-1951-40': 'Д', '4320-1951-60': 'Д',
                     '5557': 'Д', '32551': 'Д'
}
In [38]:
#Обновляем столбец "вид_топлива" в датасете auto с использованием словаря
auto['вид_топлива'] = auto['вид_топлива'].fillna(auto['модель'].map(fuel_type))
In [39]:
#Проверка что из этого получилось
auto['вид_топлива'].unique()
Out[39]:
array(['Б', 'Д', 'Г', 'Э'], dtype=object)

Это успешный успех! Все получилось как и задумывалось, идем дальше.

In [40]:
#Разбираемся с коробкой передач!
#Съехавшее значение "передний" необходимо вернуть на место.
def type_inplace(df):
    condition = df['коробка_передач'] == 'Передний' #Условие для выбора значений 'передний' в столбце 'коробка_передач'
    df.loc[condition, 'тип_привода'] = 'передний' #Перемещение значения 'передний' из 'коробка_передач' в 'тип_привода'
    df.loc[condition, 'коробка_передач'] = np.nan #Замена на NaN

#Применяем
type_inplace(auto)

#Проверка
auto['коробка_передач'].unique()
Out[40]:
array(['4WD', nan, 'S-tronic', 'S-Tronic', 'Tiptronic', 'АКПП', 'АКП',
       'Steptronic', 'AT', '6 АТ', '5 МТ', '6АТ', 'MT', '8AT', '5МТ',
       'Powershift S6', '6AT', 'Мех.', '6 AT', '6 MT', '6MT', '5 AT',
       '5AT', 'МКПП', '7 DCT', '7DCT', '8 AT', 'МТ', 'CVT', 'DCT', '4 АТ',
       '6 МТ', '6МТ', '4АТ', '4AT', '8АТ', '8 АТ', '5MT', 'AMT',
       'CVT (вариатор)', 'CVT (вариATор)', 'CVT(вAриATор)', '7G-TRONIC',
       '9G-TRONIC', '12AT', '12АТ', '5АТ', '7АТ', '7AT', '6M/T', 'PDK',
       '8-ступ АКПП', '8', '8АКПП', '8 АКПП Tiptronic S', '7 АКПП (PDK)',
       '7 АКПП PDK', '8 АКПП (PDK)', 'АТ', 'АT', 'МT', '0', '7 DSG',
       '7DSG', '6 DSG', '6DSG', '#Н/Д', 'DSG', '6A', '6А', '5M', 'A/T',
       'M/T', 'МКП', '5М', 'М/T', ' 7 АКП', '7АКП', 'А/T', '8A', 'TDI',
       '9AT', 'РЕДУКТОР'], dtype=object)
In [41]:
# Создаем словарь для замены значений
transmission_type = {'4WD': 'AT', 'Передний': 'MT', 'S-tronic': 'RT', 'S-Tronic': 'RT', 'Tiptronic': 'RT', 'АКПП': 'AT', 'АКП': 'AT', 'Steptronic': 'RT',
                        'AT': 'AT', '6 АТ': 'AT', '5 МТ': 'MT', '6АТ': 'AT', 'MT': 'MT', '8AT': 'AT', '5МТ': 'MT', 'Powershift S6': 'RT', '6AT': 'AT',
                        'Мех.': 'MT', '6 AT': 'AT', '6 MT': 'MT', '6MT': 'MT', '5 AT': 'AT', '5AT': 'AT', 'МКПП': 'MT', '7 DCT': 'RT', '7DCT': 'RT',
                        '8 AT': 'AT', 'МТ': 'MT', 'CVT': 'RT', 'DCT': 'RT', '4 АТ': 'AT', '6 МТ': 'MT', '6МТ': 'MT', '4АТ': 'AT', '4AT': 'AT', '8АТ': 'AT',
                        '8 АТ': 'AT', '5MT': 'MT', 'AMT': 'RT', 'CVT (вариатор)': 'RT', 'CVT (вариATор)': 'RT', 'CVT(вAриATор)': 'RT', '7G-TRONIC': 'RT',
                        '9G-TRONIC': 'RT', '12AT': 'AT', '12АТ': 'AT', '5АТ': 'AT', '7АТ': 'AT', '7AT': 'AT', '6M/T': 'MT', 'PDK': 'RT', '8-ступ АКПП': 'AT',
                        '8': 'AT', '8АКПП': 'AT', '8 АКПП Tiptronic S': 'RT', '7 АКПП (PDK)': 'RT', '7 АКПП PDK': 'RT', '8 АКПП (PDK)': 'RT', 'АТ': 'AT',
                        'АT': 'AT', 'МT': 'MT', '0': 'AT', '7 DSG': 'RT', '7DSG': 'RT', '6 DSG': 'RT', '6DSG': 'RT', 'DSG': 'RT', '6A': 'AT', '6А': 'AT', '5M': 'MT',
                        'A/T': 'AT', 'M/T': 'MT', 'МКП': 'MT', '5М': 'MT', 'М/T': 'MT', ' 7 АКП': 'RT', '7АКП': 'RT', 'А/T': 'AT', '8A': 'AT', 'TDI': 'RT', '9AT': 'AT',
                        'РЕДУКТОР': 'RT'
}
In [42]:
#Замена значений в столбце 'коробка_передач' с использованием словаря
auto['коробка_передач'] = auto['коробка_передач'].replace(transmission_type)

#Проверка
auto['коробка_передач'].unique()
Out[42]:
array(['AT', nan, 'RT', 'MT', '#Н/Д'], dtype=object)

Осталось разобраться с отсутствующими знаячениями, и теми что были утрачены в следствии повреждения данных.

In [43]:
#Условие для выбора значений '#Н/Д' и NaN в столбце 'коробка_передач'
condition = (auto['коробка_передач'] == '#Н/Д') | auto['коробка_передач'].isna()

#Собираем значения в переменную not_transmission
not_transmission = auto.loc[condition]
not_transmission['коробка_передач'].info()
<class 'pandas.core.series.Series'>
Int64Index: 3022 entries, 23734 to 39947
Series name: коробка_передач
Non-Null Count  Dtype 
--------------  ----- 
4 non-null      object
dtypes: object(1)
memory usage: 47.2+ KB

Предлагаю тем же способом что и раннее восстановить данные.

In [44]:
#Группировка по модели и объединение строк с уникальными моделями
transmission = not_transmission.groupby('бренд')['модель'].unique().reset_index()

#Преобразование списков моделей в строки
transmission['модель'] = transmission['модель'].apply(lambda x: ', '.join(x))

transmission
Out[44]:
бренд модель
0 ANKAI HF-D105, HFF6850G
1 Dong Feng BWC6665GA5
2 Foton BJ3253DMPKB-AD, BJ1069VDJEA-F1
3 Hyundai Truck & Bus HD 65, HD 78, Universe, HD 35, EX8
4 Isuzu D-MAX, NMR, NPR, NQR, NMS85, NPS
5 Iveco Daily, Daily A, Daily V, Tipper
6 Jac S3, S5, N120, N75, T6, iev, N56
7 Jaguar I-Pace
8 MAN TG
9 Mazda 6, CX-5, CX-9
10 Mercedes-Benz V-Class
11 Mercedes-Benz Trucks Actros, Setra
12 Peugeot 301, Partner Panel Van
13 Ravon Nexia R3, R4
14 Renault Duster, Sandero, Kaptur, Koleos, Logan, Master...
15 Scania G-Series, P-Series, R-Series, S-Series
16 Shacman SX3258DR384
17 Toyota Corolla, HILUX DC
18 Volkswagen Polo
19 Урал 4320, 4320-1951-40, 4320-1951-60, 5557, 32551
In [45]:
models_and_transmission = {'HF-D105': 'AT', 'HFF6850G': 'AT', 'BWC6665GA5': 'AT', 'BJ3253DMPKB-AD': 'AT', 'BJ1069VDJEA-F1': 'AT', 'HD 65': 'MT', 'HD 78': 'MT',
                            'Universe': 'MT', 'HD 35': 'MT', 'EX8': 'MT', 'D-MAX': 'MT', 'NMR': 'MT', 'NPR': 'MT', 'NQR': 'MT', 'NMS85': 'MT', 'NPS': 'MT', 'Daily': 'MT',
                            'Daily A': 'MT', 'Daily V': 'MT', 'Tipper': 'MT', 'S3': 'MT', 'S5': 'MT', 'N120': 'MT', 'N75': 'MT', 'T6': 'MT', 'iev': 'MT', 'N56': 'MT',
                            'I-Pace': 'MT', 'TG': 'MT', '6': 'MT', 'CX-5': 'MT', 'CX-9': 'MT', 'V-Class': 'MT', 'Actros': 'MT', 'Setra': 'MT', '301': 'MT', 'Partner Panel Van': 'MT',
                            'Nexia R3': 'MT', 'R4': 'MT', 'Duster': 'MT', 'Sandero': 'MT', 'Kaptur': 'MT', 'Koleos': 'MT', 'Logan': 'MT', 'Master': 'MT', 'Dokker': 'MT', 'Arkana': 'MT',
                            'G-Series': 'MT', 'P-Series': 'MT', 'R-Series': 'MT', 'S-Series': 'MT', 'SX3258DR384': 'MT', 'Corolla': 'RT', 'HILUX DC': 'RT', 'Polo': 'RT', '4320': 'RT',
                            '4320-1951-40': 'RT', '4320-1951-60': 'RT', '5557': 'RT', '32551': 'RT'
}
In [46]:
#Обновляем столбец "коробка_передач" в датасете auto с использованием словаря
auto['коробка_передач'] = auto['коробка_передач'].fillna(auto['модель'].map(models_and_transmission))

#Проверка
auto['коробка_передач'].unique()
Out[46]:
array(['AT', 'MT', 'RT', '#Н/Д'], dtype=object)
In [47]:
t = auto.query('коробка_передач == "#Н/Д"')
t
Out[47]:
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
31148 2019 Февраль toyota motor kazakhstan Toyota Corolla 2019 Турция Б #Н/Д #Н/Д Нур-Султан физ. лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
31149 2019 Февраль toyota motor kazakhstan Toyota Corolla 2019 Турция Б #Н/Д #Н/Д Нур-Султан физ. лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
32670 2019 Апрель toyota motor kazakhstan Toyota HILUX DC 2019 Таиланд Б #Н/Д #Н/Д Алматы юр. лицо 1 30870.28194 30870.28194 г.Алматы Пикапы Пикап
33070 2019 Июль toyota motor kazakhstan Toyota HILUX DC 2019 Таиланд Б #Н/Д #Н/Д Атырау физ. лицо 1 27012.45730 27012.45730 Атырауская область Пикапы Пикап

Те же строки что и раннее.... Снова съехали значения, и не сохранились прошлые. Я пока это оставлю как есть, посмотрим что можно с этим сделать потом.

In [48]:
#Привод
auto['тип_привода'].unique()
Out[48]:
array(['MT', 'AT', 'передний', 'FWD', 'quattro', 'Задний', 'Полный',
       'AWD', 'Передний', '4WD', '4х2.2', nan, 'RWD', '2 WD', '2WD',
       '4 WD', '4X4', '4х4', '4x4', '4x2', '4х2', '4X2', 'Астана',
       'Передний (FF)', '0', 'FF', '#Н/Д', 'полный', '4Motion'],
      dtype=object)

Астану запихать в регион, остальное классифицировать.

In [49]:
#Список со старыми значениями
transmission_list = ['MT', 'AT', 'передний', 'FWD', 'quattro', 'Задний', 'Полный',
                     'AWD', 'Передний', '4WD', '4х2.2', 'RWD', '2 WD', '2WD',
                     '4 WD', '4X4', '4х4', '4x4', '4x2', '4х2', '4X2', 'Передний (FF)',
                     '0', 'FF', 'полный', '4Motion']

#Новый список со значениями
drive_code_list = []

for transmission in transmission_list:
    if transmission in ['FWD', 'передний', 'Передний (FF)', '2WD']:
        drive_code_list.append('FWD')
    elif transmission in ['Задний', 'RWD']:
        drive_code_list.append('RWD')
    elif transmission in ['Полный', 'AWD', '4WD', '4X4', '4х4', '4x4', '4x2', '4х2', '4X2', 'quattro', 'полный', '4Motion']:
        drive_code_list.append('AWD')
    elif transmission in ['AT', 'Автоматический привод']:
        drive_code_list.append('AWD')
    else:
        drive_code_list.append(np.nan)

#Заменяем значения в столбце "тип привода" в датафрейме auto
auto['тип_привода'] = auto['тип_привода'].replace(dict(zip(transmission_list, drive_code_list)))
In [50]:
#Убираем из столбца Астану
auto.loc[auto['тип_привода'] == 'Астана', 'тип_привода'] = np.nan
auto.loc[auto['регион'] == 'Астана', 'регион'] = np.nan
In [51]:
#Проверка значений
auto['тип_привода'].unique()
Out[51]:
array([nan, 'AWD', 'FWD', 'RWD', '#Н/Д'], dtype=object)

Создам датасет с отсутствующими и поврежденными данными

In [52]:
not_drive = auto[auto['тип_привода'].isin(['#Н/Д', np.nan])]

Заполним значения по моделям

In [53]:
#Проверка поврежденных значений
n = not_drive.query('тип_привода == "#Н/Д"')
n
Out[53]:
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
31148 2019 Февраль toyota motor kazakhstan Toyota Corolla 2019 Турция Б #Н/Д #Н/Д Нур-Султан физ. лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
31149 2019 Февраль toyota motor kazakhstan Toyota Corolla 2019 Турция Б #Н/Д #Н/Д Нур-Султан физ. лицо 1 42316.46043 42316.46043 г.Нур-Султан Легковые автомобили C класс
32670 2019 Апрель toyota motor kazakhstan Toyota HILUX DC 2019 Таиланд Б #Н/Д #Н/Д Алматы юр. лицо 1 30870.28194 30870.28194 г.Алматы Пикапы Пикап
33070 2019 Июль toyota motor kazakhstan Toyota HILUX DC 2019 Таиланд Б #Н/Д #Н/Д Атырау физ. лицо 1 27012.45730 27012.45730 Атырауская область Пикапы Пикап

Те же проблемные модели) пожалуй, я от них избавлюсь

Надо сформировать список с моделями для заполнения его данными.

In [54]:
#Список уникальных моделей с отсутствующими значениями
drive_type_dict = {
    'Duster': 'FWD', 'Sandero': 'FWD', 'A3': 'AWD', 'A4': 'AWD', 'A6': 'AWD', 'A7': 'AWD', 'A8': 'AWD',
    'Q5': 'AWD', 'Q7': 'AWD', '3 серия': 'RWD', '5 серия': 'RWD', '6 серия': 'RWD', '7 серия': 'RWD',
    'X1': 'AWD', 'X3': 'AWD', 'X4': 'AWD', 'X5': 'AWD', 'X6': 'AWD', 'X7': 'AWD', 'Z4': 'RWD',
    'Aveo': 'FWD', 'Captiva': 'AWD', 'Niva': '4WD', 'Tahoe': '4WD', 'Tracker': 'FWD', 'BS 106 A': 'FWD',
    'Fiesta': 'FWD', 'Mondeo': 'FWD', 'BJ3253DMPKB-AD': 'RWD', '2217': 'RWD', '2310': 'RWD', '2705': 'RWD',
    '2752': 'RWD', '3221': 'RWD', '3302': 'RWD', '3308': 'RWD', '3309': 'RWD', 'Next': 'RWD',
    'Accent': 'FWD', 'Creta': 'FWD', 'Elantra': 'FWD', 'Santa Fe': 'AWD', 'Sonata': 'FWD', 'TQ-1/H-1': 'RWD',
    'County': 'RWD', 'H350': 'RWD', 'HD 170': 'RWD', 'HD 65': 'RWD', 'HD 78': 'RWD', 'Universe': 'RWD',
    'Tucson': 'AWD', 'Q50': 'AWD', 'QX50': 'AWD', 'QX60': 'AWD', 'QX80': 'AWD', 'D-MAX': '4WD',
    'NMR': 'RWD', 'NPR': 'RWD', 'Daily': 'RWD', 'Daily A': 'RWD', 'Daily V': 'RWD', 'Stralis': 'RWD',
    'Tipper': 'RWD', 'S3': 'RWD', 'S5': 'RWD', 'F-Pace': 'AWD', 'F-Type': 'RWD', 'XE': 'RWD',
    'XF': 'RWD', 'XJ': 'RWD', '4308': 'RWD', '4311': 'RWD', '43118': 'RWD', '43253': 'RWD',
    '43502': 'RWD', '44108': 'RWD', '45142': 'RWD', '45143': 'RWD', '53215': 'RWD', '53504': 'RWD',
    '53605': 'RWD', '54115': 'RWD', '5490': 'RWD', '65111': 'RWD', '65115': 'RWD', '65116': 'RWD',
    '65117': 'RWD', '6520': 'RWD', '65206': 'RWD', '65225': 'RWD', '66052': 'RWD', '6606': 'RWD',
    'Cerato': 'FWD', 'Optima': 'FWD', 'Picanto': 'FWD', 'Quoris': 'FWD', 'Rio': 'FWD', 'Sorento': 'AWD',
    'Soul': 'FWD', 'Sportage': 'AWD', '4x4': '4WD', 'Granta': 'FWD', 'Kalina': 'FWD', 'Largus': 'FWD',
    'Vesta': 'FWD', 'XRAY': 'FWD', 'ВИС': 'RWD', 'Discovery': 'AWD', 'Discovery Sport': 'AWD',
    'Range Rover': 'AWD', 'Range Rover Evoque': 'AWD', 'Range Rover Sport': 'AWD', 'ES': 'FWD',
    'GX': 'AWD', 'LS': 'RWD', 'LX': 'AWD', 'NX': 'AWD', 'RX': 'AWD', 'RXH': 'AWD', 'Murman': 'FWD',
    'Solano': 'FWD', 'X50': 'FWD', 'X60': 'FWD', 'TG': 'RWD', '6': 'FWD', 'CX-5': 'AWD', 'A-Class': 'FWD',
    'C-Class': 'RWD', 'CLA-Class': 'FWD', 'CLS-Class': 'RWD', 'E-Class': 'RWD', 'G-Class': 'AWD',
    'GLA-Class': 'FWD', 'GLC-Class': 'AWD', 'GLE-Class': 'AWD', 'GLS-Class': 'AWD', 'S-Class': 'RWD',
    'Actros': 'RWD', 'Sprinter': 'RWD', 'Tourismo': 'RWD', 'V-Class': 'RWD', 'Vito': 'RWD', 'Countryman': 'AWD',
    'ASX': 'AWD', 'Outlander': 'AWD', 'Pajero IV': '4WD', 'Pajero Sport': '4WD', 'Almera': 'FWD',
    'Juke': 'FWD', 'Murano': 'AWD', 'Qashqai': 'FWD', 'Terrano': '4WD', 'X-Trail': '4WD', '301': 'FWD',
    'Partner Panel Van': 'FWD', '911 Carrera S': 'RWD', 'Cayenne': 'AWD', 'Macan': 'AWD', 'Panamera': 'RWD',
    'Nexia R3': 'FWD', 'R4': 'FWD', 'Kaptur': 'FWD', 'Koleos': '4WD', 'Logan': 'FWD', 'Master': 'RWD',
    'G-Series': 'RWD', 'P-Series': 'RWD', 'R-Series': 'RWD', 'Octavia': 'FWD', 'Rapid': 'FWD', 'Superb': 'AWD',
    'Forester': 'AWD', 'Legacy': 'AWD', 'Outback': 'AWD', 'XV': 'AWD', 'Camry': 'FWD', 'Corolla': 'FWD',
    'HIGHLANDER': 'AWD', 'HILUX DC': '4WD', 'LC Prado': '4WD', 'LC200': '4WD', 'RAV4': 'AWD', '2206': 'RWD',
    '3151': 'RWD', '3303': 'RWD', '3741': 'RWD', '3909': 'RWD', '3962': 'RWD', 'Cargo': 'RWD', 'Patriot': '4WD',
    'Patriot Pickup': '4WD', 'Amarok': '4WD', 'Caddy Kasten ': 'FWD', 'Caddy Maxi Kombi': 'FWD', 'Caravelle': 'AWD',
    'Jetta': 'FWD', 'Multivan': 'AWD', 'Polo': 'FWD', 'Tiguan': 'AWD', 'Touareg': 'AWD', 'Transporter': 'RWD',
    'Transporter Kasten': 'RWD', 'XC90': 'AWD', '4320': 'RWD', '4320-1951-40': 'RWD', '4320-1951-60': 'RWD',
    '5557': 'RWD', 'MYWAY': 'FWD', 'CX-9': 'AWD', 'HD 35': 'RWD', 'Range Rover Velar': 'AWD', 'BS 106 D': 'FWD',
    'Kodiaq': 'AWD', 'Escalade': 'AWD', 'GLC Coupe': 'AWD', 'X200': '4WD', 'E-PACE': 'AWD', 'Dokker': 'FWD',
    'Eclipse Cross': 'AWD', 'X70': 'FWD', 'N120': 'RWD', 'N75': 'RWD', 'T6': 'AWD', 'SX3258DR384': 'RWD',
    'iev': 'FWD', 'S-Series': 'RWD', 'NQR': 'RWD', 'X2': 'AWD', 'S90': 'AWD', 'XC60': 'AWD', 'C-HR': 'FWD',
    '300': 'RWD', 'XC40': 'AWD', 'N56': 'RWD', 'XT5': 'AWD', '500': 'FWD', 'Stinger': 'RWD', 'Hatch': 'FWD', 
    'Traverse': 'AWD', 'NMS85': 'RWD', 'BJ1069VDJEA-F1': 'RWD', 'HD 79': 'RWD', 'BWC6665GA5': 'RWD',
    'i8': 'AWD', 'UX': 'AWD', '8 серия': 'RWD', 'Cabrio': 'FWD', 'HF-D105': 'FWD', 'NPS': 'RWD', 'Q8': 'AWD',
    'RS5': 'AWD', 'Teramont': 'AWD', '5299': 'RWD', 'I-Pace': 'AWD', 'S7': 'AWD', '45141': 'RWD', '32551': 'RWD',
    'BC 211 MA': 'RWD', 'EX8': 'RWD', 'BC 095': 'RWD', 'Camaro': 'RWD', 'HFF6850G': 'RWD', 'Transporter Kombi ': 'RWD'
}

#Обновляем столбец "тип_привода" в датасете auto с использованием словаря
auto['тип_привода'] = auto['тип_привода'].fillna(auto['модель'].map(drive_type_dict))
In [55]:
auto = inform(auto)
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
23723 2019 Январь renault россия Renault Duster 2019 Российская Федерация Б 2 AT FWD Уральск юр. лицо 1 12249.61125 12249.61125 Западно-Казахстанская область Внедорожники Субкомпактные SUV
23724 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Нур-Султан юр. лицо 1 12249.61125 12249.61125 г.Нур-Султан Внедорожники Субкомпактные SUV
23725 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Нур-Султан юр. лицо 1 12249.61125 12249.61125 г.Нур-Султан Внедорожники Субкомпактные SUV
23726 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Кызылорда юр. лицо 1 12249.61125 12249.61125 Кызылординская область Внедорожники Субкомпактные SUV
23727 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT FWD Караганда юр. лицо 1 12249.61125 12249.61125 Карагандинская область Внедорожники Субкомпактные SUV
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39465 entries, 23723 to 39965
Data columns (total 19 columns):
 #   Column           Non-Null Count  Dtype  
---  ------           --------------  -----  
 0   год              39465 non-null  int64  
 1   месяц            39465 non-null  object 
 2   компания         39465 non-null  object 
 3   бренд            39465 non-null  object 
 4   модель           39465 non-null  object 
 5   год_выпуска      39465 non-null  int32  
 6   производитель    39465 non-null  object 
 7   вид_топлива      39465 non-null  object 
 8   объем_двигателя  39465 non-null  object 
 9   коробка_передач  39465 non-null  object 
 10  тип_привода      39394 non-null  object 
 11  регион           39465 non-null  object 
 12  тип_клиента      39465 non-null  object 
 13  количество       39465 non-null  int32  
 14  цена_usd         39465 non-null  float64
 15  продажа_usd      39465 non-null  float64
 16  область          39465 non-null  object 
 17  сегментация      39465 non-null  object 
 18  класс            39465 non-null  object 
dtypes: float64(2), int32(2), int64(1), object(14)
memory usage: 6.7+ MB

Количество дубликатов: 22070

Число пропусков:
 год                 0
месяц               0
компания            0
бренд               0
модель              0
год_выпуска         0
производитель       0
вид_топлива         0
объем_двигателя     0
коробка_передач     0
тип_привода        71
регион              0
тип_клиента         0
количество          0
цена_usd            0
продажа_usd         0
область             0
сегментация         0
класс               0
dtype: int64

Доля пропусков:
 год                0.000000
месяц              0.000000
компания           0.000000
бренд              0.000000
модель             0.000000
год_выпуска        0.000000
производитель      0.000000
вид_топлива        0.000000
объем_двигателя    0.000000
коробка_передач    0.000000
тип_привода        0.179906
регион             0.000000
тип_клиента        0.000000
количество         0.000000
цена_usd           0.000000
продажа_usd        0.000000
область            0.000000
сегментация        0.000000
класс              0.000000
dtype: float64 1

На этом предобработка завершена. Остались последние штрихи. Были удалены лишние столбцы дублирующие информацию, оставшиеся приведены к snake_case стилю для удобства работы с ними, числа приведены к нужным типам данных, неявные дубликаты заменены на корректные значения, восстановлены и сокращены (для оптимзации скорости загрузки датасета) типы привода к единому обозначению, сокращены (для опримизации скорости загрузки датасета) обозначения вида топлива, заполнены пропуски значений с задачей максимально сберечь данные в датасете.

Мной принято решение удалить пропущенные строки в столбце тип привода (0.18% от общего объема данных, мы ничего не теряем), т.к. роли для анализа они не играют никакой а эстетику портят :) Полные дубли которые оказались в датасете из-за отсутствия id индексации строк я оставляю, без них исказится дальнейший анализ.

In [56]:
#Избавлюсь от 0.18% пропусков в типе привода
clean_auto = auto.dropna()
In [57]:
#Инфо о чистом датасете
clean_auto = inform(clean_auto)
год месяц компания бренд модель год_выпуска производитель вид_топлива объем_двигателя коробка_передач тип_привода регион тип_клиента количество цена_usd продажа_usd область сегментация класс
23723 2019 Январь renault россия Renault Duster 2019 Российская Федерация Б 2 AT FWD Уральск юр. лицо 1 12249.61125 12249.61125 Западно-Казахстанская область Внедорожники Субкомпактные SUV
23724 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Нур-Султан юр. лицо 1 12249.61125 12249.61125 г.Нур-Султан Внедорожники Субкомпактные SUV
23725 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Нур-Султан юр. лицо 1 12249.61125 12249.61125 г.Нур-Султан Внедорожники Субкомпактные SUV
23726 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT AWD Кызылорда юр. лицо 1 12249.61125 12249.61125 Кызылординская область Внедорожники Субкомпактные SUV
23727 2019 Январь renault россия Renault Duster 2018 Российская Федерация Б 2 AT FWD Караганда юр. лицо 1 12249.61125 12249.61125 Карагандинская область Внедорожники Субкомпактные SUV
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39394 entries, 23723 to 39950
Data columns (total 19 columns):
 #   Column           Non-Null Count  Dtype  
---  ------           --------------  -----  
 0   год              39394 non-null  int64  
 1   месяц            39394 non-null  object 
 2   компания         39394 non-null  object 
 3   бренд            39394 non-null  object 
 4   модель           39394 non-null  object 
 5   год_выпуска      39394 non-null  int32  
 6   производитель    39394 non-null  object 
 7   вид_топлива      39394 non-null  object 
 8   объем_двигателя  39394 non-null  object 
 9   коробка_передач  39394 non-null  object 
 10  тип_привода      39394 non-null  object 
 11  регион           39394 non-null  object 
 12  тип_клиента      39394 non-null  object 
 13  количество       39394 non-null  int32  
 14  цена_usd         39394 non-null  float64
 15  продажа_usd      39394 non-null  float64
 16  область          39394 non-null  object 
 17  сегментация      39394 non-null  object 
 18  класс            39394 non-null  object 
dtypes: float64(2), int32(2), int64(1), object(14)
memory usage: 5.7+ MB

Количество дубликатов: 22019

Число пропусков:
 год                0
месяц              0
компания           0
бренд              0
модель             0
год_выпуска        0
производитель      0
вид_топлива        0
объем_двигателя    0
коробка_передач    0
тип_привода        0
регион             0
тип_клиента        0
количество         0
цена_usd           0
продажа_usd        0
область            0
сегментация        0
класс              0
dtype: int64

Доля пропусков:
 год                0.0
месяц              0.0
компания           0.0
бренд              0.0
модель             0.0
год_выпуска        0.0
производитель      0.0
вид_топлива        0.0
объем_двигателя    0.0
коробка_передач    0.0
тип_привода        0.0
регион             0.0
тип_клиента        0.0
количество         0.0
цена_usd           0.0
продажа_usd        0.0
область            0.0
сегментация        0.0
класс              0.0
dtype: float64 1
In [58]:
#Дашборд с чистыми данными (чтобы открыть, нужно убрать #)
my_report = sv.analyze(clean_auto)
#my_report.show_html()

Таким образом проведена комплексная очистка датасета и восстановление утраченных данных, с попыткой сохранить максимум имеющейся информации. Проводя предобработку у меня появилось несколько рекомендаций для сбора, чтобы в будущем повысить качество данных, ускорить предобработку аналитикам, а так же оптимизировать ввод информации сотрудникам автосалонов.

  • Рекомендую ввести индексацию строк присваивая уникальный id для каждой. Это избавит массив данных от множества явных дубликатов, искать информацию станет легче.

  • Рекомендую заблокировать возможность ручного ввода информации о характеристиках автомобиля. Необходимо сделать выпадающее окно с вариантами выбора вида топлива, типа привода, коробки передач. Таким образом мы получим стандарт введения информации в базу данных, что позволит быстро ориентироваться в них и оперативно собирать статистику. Так же это облегчит жизнь аналитикам данных.

  • Рекомендую вести учет информации в единой БД. При объединении данных хранящихся на разных сервисах/облаках неизбежно возникают съехавшие значения, ошибки при выгрузке данных, а так же может быть утеряна часть этих данных. Это позволит иметь быстрый доступ к архивам без надобности склеивать данные, убережет их от возникновения части ошибок при выгрузке.

Из 39 965 сток изначального датасета auto осталось 39 950 строк в датасете clean_auto. Данные не пострадали, очищенный датасет может использоваться для построения дашборда.

Выгрузка чистого датасета¶

In [59]:
#Название датасета в переменную csv_filename
csv_filename = 'clean_auto.csv'
clean_auto.to_csv(csv_filename, index=False) #

#Создание ссылки для скачивания
download_link = FileLink(csv_filename)

#Отображение ссылки для загрузки датасета
download_link
Out[59]:
clean_auto.csv

Исследовательский анализ данных¶

В исследовательсвом анализе данных я постараюсь раскрыть несколько важных моментов при анализе авторынка разделив его на коммерческий и некоммерческий транспорт. План действий следующий:

  • Продажи по брендам, сегментам коммерческого и некоммерческого авто

  • Модели-лидеры на рынке

  • Продажи по регионам

  • Продажи автоцентров

Продажи по брендам, сегментам коммерческого и некоммерческого авто¶

In [60]:
#Создание нового столбца с датой, для того чтобы корректно отображать графики
#Преобразование года к строковому типу, месяц в нижний регистр
clean_auto['год'] = clean_auto['год'].astype(str)
clean_auto['месяц'] = clean_auto['месяц'].str.lower()

#Словарь для замены названий месяцев
months_list = ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь']
new_months = list(range(1, 10))
months_change_dict = {k: '0' + str(v) for k, v in zip(months_list, new_months)}

#Применение словаря к столбцу 'месяц'
clean_auto['месяц'] = clean_auto['месяц'].str.lower().map(months_change_dict)

#Объединение 'год' и 'месяц' в 'дата_продажи'
clean_auto['дата_продажи'] = clean_auto['год'] + '-' + clean_auto['месяц']

#Преобразование 'дата_продажи' в datetime
clean_auto['дата_продажи'] = pd.to_datetime(clean_auto['дата_продажи'], errors='coerce')

clean_auto['дата_продажи'].unique()
Out[60]:
array(['2019-01-01T00:00:00.000000000', '2019-05-01T00:00:00.000000000',
       '2019-08-01T00:00:00.000000000', '2019-04-01T00:00:00.000000000',
       '2019-07-01T00:00:00.000000000', '2019-02-01T00:00:00.000000000',
       '2019-06-01T00:00:00.000000000', '2019-09-01T00:00:00.000000000',
       '2019-03-01T00:00:00.000000000'], dtype='datetime64[ns]')
In [61]:
#Сразу разделю транспорт на коммерцию и бытовое пользование, эт в будущем пригодится
#Здесь живет коммерческий транспорт
auto_com = clean_auto[clean_auto['сегментация'] == 'Коммерческие автомобили']

#Народная выборка! Все для людей :)
auto_child = clean_auto[clean_auto['сегментация'] != 'Коммерческие автомобили']
In [62]:
#Создам сводную таблицу с количеством продаж каждого сегмента транспорта
all_auto = clean_auto.groupby('сегментация')['количество'].sum().reset_index()
all_auto = all_auto.sort_values(by='количество', ascending=False)
all_auto
Out[62]:
сегментация количество
2 Легковые автомобили 23288
0 Внедорожники 21458
1 Коммерческие автомобили 5102
3 Минивэны 1819
4 Пикапы 975
In [63]:
#Построение графика отображающего сводную таблицу
fig = px.bar(all_auto, x='сегментация', y='количество', color='сегментация', text = 'количество',
            color_discrete_sequence=px.colors.qualitative.Prism)

fig.update_layout(title='Проданные автомобили разбитые по сегментам',
                 xaxis_title='Сегмент',
                 yaxis_title='количество продаж')
fig.show()

Чаще всего приобретались легковые авто и внедорожники. Это логично, т.к. салоны торгующие авто больше направлены на аудиторию гражданского населения, нежели на удовлетворение спроса коммерческих нужд. Более того, крупные коммерческие организации заключают контракт на прямую с заводами производителями авто, те в свою очередь могут предлагать более выгодные условия для организации нежели диллер.

Минивэны и пикапы автомобили специфичные. Например, минивэн может заинтересовать семьи с тремя и более детьми (коих не так уж и много на этой планете), пикапы удобны для жизни за городом, в местностях с тяжелой проходимостью, для людей нуждающихся в относительно большой грузоподъемности и мощности авто. Отсюда и наблюдаем не такую высокую популярность данных сегментов.

Рассмотрим самые популярные бренды автомобилей пользующиеся спросом у населения. Здесь понадобится уже собранный датафрейм без участия коммерческого транспорта.

In [64]:
#Таблица с брендами. Пусть это будет топ 10 брендов
brend = auto_child.groupby('бренд')['количество'].sum().reset_index()
brend = brend.sort_values(by='количество', ascending=False)
brend = brend.head(10)
brend
Out[64]:
бренд количество
11 Lada 11092
26 Toyota 10745
5 Hyundai 10168
10 Kia 2358
22 Ravon 1785
23 Renault 1741
8 Jac 1686
19 Nissan 1664
13 Lexus 1206
24 Skoda 791
In [65]:
#Построение графика отображающего сводную таблицу
fig = px.bar(brend, x='бренд', y='количество', color='бренд', text = 'количество',
            color_discrete_sequence=px.colors.qualitative.Prism)

fig.update_layout(title='Топ авто по брендам у населения',
                 xaxis_title='Бренды',
                 yaxis_title='количество продаж')
fig.show()

Я удивлен. Лада фаворит:) Видно что с большим отрывом лидируют такие бренды как Lada, Tayota, Hyundai. Это можно объяснить широкой доступностью расходников и запчастей на данные марки, привлекательной ценой (в этом плане выигрывает Лада у всех), а у Тайоты и Хёндая высочайший срок службы. Эти автомобили не дорогие в обслуживании, долговечные (долговечность не про Ладу), а от того и покорили сердца населения. Рассматривать другие бренды не счичтаю целесообразным, т.к. разница в объеме продаж колоссальна.

Рассмотрим так же бренды коммерческих авто.

In [66]:
#Таблица с брендами. Пусть это будет топ 10 брендов
brend_com = auto_com.groupby('бренд')['количество'].sum().reset_index()
brend_com = brend_com.sort_values(by='количество', ascending=False)
brend_com = brend_com.head(10)
brend_com
Out[66]:
бренд количество
4 GAZ 1821
10 KAMAZ 877
17 UAZ 844
0 ANKAI 300
9 Jac 192
2 Dong Feng 160
1 Daewoo 146
7 Isuzu 125
6 Hyundai Truck & Bus 109
16 Shacman 101
In [67]:
#Построение графика отображающего сводную таблицу
fig = px.bar(brend_com, x='бренд', y='количество', color='бренд', text = 'количество',
            color_discrete_sequence=px.colors.qualitative.Prism)

fig.update_layout(title='Топ авто по брендам у коммерции',
                 xaxis_title='Бренды',
                 yaxis_title='количество продаж')
fig.show()

GAZ, KAMAZ, UAZ самые популярные авто для коммерции. GAZ пользуется спросом у спецслужб (скорая, полиция), Камазы распространены в строительных организациях и транспортных компаниях, Уазики гибки в использовании, их линейка коммерческого транспорта имеет как авто для перемещения пассажиров, так и грузовые авто до 3.5 тон.

ANKAI, Dong Feng, Daewoo, Isuzu - это пассажирские автобусы. Автопарк пополняют обычно по мере списания старых авто :) потому продажи не такие активные.

Динамика продаж¶

Теперь я рассмотрю динамику продаж транспорта в денежном эквиваленте за весь временной период который мы имеем в датасете.

In [68]:
#Подготовка данных для построения графика
line_graph = clean_auto.groupby('дата_продажи')['продажа_usd'].sum().reset_index()

cum_line_graph = clean_auto.groupby('дата_продажи')['продажа_usd'].sum().reset_index()
cum_line_graph['продажа_usd'] = cum_line_graph['продажа_usd'].cumsum()
In [69]:
#Создаю график с динамикой и объемом продаж
fig, ax1 = plt.subplots(figsize=(12, 6))

#Динамика
ax1.plot(line_graph['дата_продажи'],
         line_graph['продажа_usd']/1000000,
         linewidth=2,
         color='crimson',
         marker='s',
         label='Динамика продаж по месяцам')

ax1.set_xlabel('Месяц продажи')
ax1.set_ylabel('Объем продаж, млн.$', color='crimson')
ax1.tick_params(axis='y', labelcolor='crimson')

#Подписи для динамики
for x, y in zip(line_graph['дата_продажи'], line_graph['продажа_usd']/1000000):
    ax1.annotate(f'{y:.2f}', (x, y), textcoords="offset points", xytext=(-10,5), ha='center')

#Создаем вторую ось Y
ax2 = ax1.twinx()

#Емкость рынка
ax2.plot(cum_line_graph['дата_продажи'],
         cum_line_graph['продажа_usd']/1000000,
         linewidth=2,
         color='#0492C2',
         marker='o',
         linestyle='--',
         label='Динамика емкости рынка')

#Подписи для емкости
for x, y in zip(cum_line_graph['дата_продажи'], cum_line_graph['продажа_usd']/1000000):
    ax2.annotate(f'{y:.2f}', (x, y), textcoords="offset points", xytext=(-5,0), ha='right', va='baseline', color='#0492C2')

#Названия осей и графика
plt.title('Динамика объема продаж автомобилей в Казахстане в 2019 году (млн.USD)')
plt.xlabel('Месяц продажи')
plt.ylabel('Объем продаж, млн.$')
plt.xticks()

ax2.set_ylabel('Динамика емкости рынка', color='#0492C2')
ax2.tick_params(axis='y', labelcolor='#0492C2')

fig.tight_layout()
plt.show()

Таким образом мы видим что динамика емкости рынка к сентябрю 2019го составила 1 миллиард 321 миллион долларов, прирост был плавным на протяжении всего периода. А вот объем продаж показывает немного другую картину. Самый провальный оказался февраль (109.59 млн за месяц), и это можно объяснить закономерностью продаж в большинстве сфер торговли (февраль как правило в ряде сфер считается месяцем с самым низким показателем продаж), самый высокий показатель в июле (199.68 млн за месяц). с февраля по июнь наблюдается относительно равная картина восстановления объема продаж перед грядущей аномалией, следом после всплеска произошло падение до 153.38 млн в августе, и график снова постепенно стал возвращаться в норму чему следует увеличившийся объем в сентябре до 157.61 млн.

В 2019 году казахстанский авторынок показал самый высокий результат за последние семь лет – официальные дилеры реализовали 123 778 автомобилей. Однако, конкретная причина всплеска продаж в июле 2019 года не была мной найдена. Возможно, всплеск продаж был связан с общими тенденциями роста в этом году, ведь было реализовано 76 217 новых автомобилей, а это на 22% больше чем в 2018 году. Поскольку самыми продаваемыми моделями в 2019 году в Казахстане стали автомобили Toyota Camry, я так же могу предположить что это связано с поставкой диллерам в салоны этой модели... Ажиотаж к покупке данной модели мог привести к повышенной активности населения в июле, но проверить информацию не предоставляется возможным.

👇 Источники информации ниже по ссылкам 👇

Официальный инфо сайт Премьер-министра Казахстана

Forbes Kazahstan

Визуализация продаж по автоцентрам¶

Считаю целесообразным изучить информацию о продажах по диллерам. Это даст понимание где и у кого лучше продаются авто. Изучив это можно начинать разрабатывать стратегию по увеличению объема продаж и захвата целевой аудитории.

In [70]:
#Группировка компаний и количества продаж
company_child = clean_auto.groupby('компания')['количество'].sum().reset_index()
company_child = company_child.sort_values(by='количество', ascending=False)
company_child = company_child.head(10)
company_child
Out[70]:
компания количество
25 бипэк авто 15132
19 toyota motor kazakhstan 11951
2 astana motors 10169
26 вираж 2909
0 allur auto 2415
12 nissan manufacturing rus 1760
14 renault россия 1741
13 ravon motors kazakstan 1507
30 тк камаз 878
10 mercur auto 650
In [71]:
#Для первого круга топ-3 компании
labels_top3 = company_child['компания'][:3]
values_top3 = company_child['количество'][:3]

#Остальные компании для второго круга
labels_rest = company_child['компания'][3:]
values_rest = company_child['количество'][3:]

#Круговая диаграмма с топ-3 компаниями
fig_top3 = go.Figure(go.Pie(labels=labels_top3, values=values_top3, 
                            textinfo='label+percent', 
                            marker=dict(colors=px.colors.sequential.GnBu_r),
                            name="Доля продаж топ-3 компаний",
                            insidetextorientation='radial'))

#Круговая диаграмма с остальными компаниями
fig_rest = go.Figure(go.Pie(labels=labels_rest, values=values_rest, 
                            textinfo='label+percent', 
                            marker=dict(colors=px.colors.sequential.GnBu_r),
                            name="Доля продаж остальных компаний",
                            insidetextorientation='radial'))

#Две диаграммы на одном графике
fig = make_subplots(1, 2, specs=[[{'type':'domain'}, {'type':'domain'}]],
                    subplot_titles=['Доля продаж топ-3 компаний', 'Доля продаж остальных компаний'])

#Добавление диаграмм на график
fig.add_trace(fig_top3.data[0], 1, 1)
fig.add_trace(fig_rest.data[0], 1, 2)

#Управление размерами и расположением заголовка
fig.update_layout(showlegend=True, title_text="Доли продаж по компаниям", height=600, width=1200, title_x=0.5)
fig.show()

Бипэк авто, крупнейший холдинг имеющий самую большую долю авторынка Казахстана (40.6%). На тот момент ничего не предвещало беды, но уже в конце 2019 Бипэк уходит с рынка. Помимо нблюдаем дистрибьютора Tayota motor kazahstan (32.1% рынка) и astana motors (27.3%). Доля остальных диллеров существенно ниже, рассматривать их не имеет целесообразности.

Т.к. нас интересует Mercur Auto, следует отметить что в топе этот диллер находится на последнем месте, занимая лишь 5.5% рынка.

Общие продажи по регионам¶

In [72]:
#Таблица с топом регионов где осуществлялись продажи
top_region = clean_auto.groupby('регион')['количество'].sum().reset_index()
top_region = top_region.sort_values(by='количество', ascending=False)
top_region = top_region.head(10)
top_region
Out[72]:
регион количество
2 Алматы 13533
11 Нур-Султан 9976
23 Шымкент 3728
3 Атырау 3311
8 Костанай 3156
5 Караганда 2843
21 Уральск 2128
22 Усть-Каменогорск 2096
0 Актау 2049
1 Актобе 1794
In [73]:
#Строим самый красивый на свете график
fig = px.bar(top_region, x='количество', y='регион', color='регион', text ='количество',
            color_discrete_sequence=px.colors.qualitative.Prism)

fig.update_layout(title='Общее количество продаж по регионам',
                 xaxis_title='Количество продаж',
                 yaxis_title='Названия регионов')
fig.show()

Лидеры общих продаж по регионам Алматы (13533 продаж) и Нур-Султан (9876 продаж). В средних значениях от 3156 до 3728 продаж держатся Костанай, Атырау, и Шымкент.

Анализ положения Меркур Авто¶

Анализ положения Меркур Авто позволит сделать выводы, и построить рекомендации для улучшения показателей продаж, а так же понимания на что стоит обратить внимание в дальнейшем.

План действий:

  • Выручка: общая, по маркам, средняя, ежемесячная, ежемесячная по маркам
  • Продажи по регионам: общие, по маркам
  • BCG анализ

Общая и средняя выручка¶

In [74]:
#Фильтрация по компании. Оставим только Меркур Авто
mer_auto = clean_auto.query('компания == "mercur auto"')
In [75]:
#Сводная таблица с общими продажами по месяцам(пригодится для построения графика)
sales_month = mer_auto.groupby('месяц')['продажа_usd'].sum().reset_index()
sales_month['продажа_usd'] = sales_month['продажа_usd'].round(2)
In [76]:
#Общая и средняя выручка
print('Общая выручка:', mer_auto['продажа_usd'].sum().round(2))
print()
print('Средняя выручка в месяц:', round(sales_month['продажа_usd'].mean(), 2))
Общая выручка: 19355275.98

Средняя выручка в месяц: 2150586.22

Общая выручка за весь период с января по сентябрь 2019го года у компании Mercur Auto составила 19 355 276 usd. Средняя ежемесячная выручка составляет 2 150 586 usd.

Продажи по месяцам¶

In [77]:
#Верну месяцам названия, чтобы график выглядел приличнее
sales_month['месяц'] = sales_month['месяц'].replace({'01': 'Январь', '02': 'Февраль', '03': 'Март', '04': 'Апрель',
                                            '05': 'Май', '06': 'Июнь', '07': 'Июль', '08': 'Август', '09': 'Сентябрь'})

sales_month
Out[77]:
месяц продажа_usd
0 Январь 2979406.65
1 Февраль 2949383.66
2 Март 2707627.00
3 Апрель 2667282.58
4 Май 3687779.06
5 Июнь 835751.00
6 Июль 1386826.00
7 Август 1110374.04
8 Сентябрь 1030846.00
In [78]:
#Построение графика отображающего сводную таблицу
fig = px.bar(sales_month, x='месяц', y='продажа_usd', color='месяц', text = 'продажа_usd',
            color_discrete_sequence=px.colors.qualitative.Prism)

fig.update_layout(title='Общая сумма продаж по месяцам',
                 xaxis_title='Месяц',
                 yaxis_title='Сумма продаж')
fig.show()

Выведя график с суммой общих продаж по месяцам наблюдается хороший уровень начала года имеющий слегка понижающийся тренд, затем резкий скачок в мае (3 687 779 usd, самый высокий показатель за весь временной диапазон), и существенная просадка выручки в летне-осенний период. Что послужило причиной аномалии в мае? Пока не могу предположить причины произошедшего, построю график с количеством единиц брендов продаваемых в Меркур Авто, и заодно выведу отдельный график с суммой продаж этих машин в каждом месяце.

Продажи по брендам¶

In [79]:
#Количество продаваемых авто каждого бренда с суммой выручки
top_auto = mer_auto.groupby('бренд')[['количество', 'продажа_usd']].sum().reset_index()
top_auto['продажа_usd'] = top_auto['продажа_usd'].round(2)
top_auto = top_auto.sort_values(by='продажа_usd', ascending=False)

top_auto
Out[79]:
бренд количество продажа_usd
2 Volkswagen 546 10182272.86
1 Porsche 52 5113512.70
0 Audi 52 4059490.43
In [80]:
#Круговые диаграммы с долей по количеству и продажам
#Диаграмма по количеству
fig_quantity = go.Figure(go.Pie(labels=top_auto['бренд'], values=top_auto['количество'],
                                textinfo='label+percent', marker=dict(colors=px.colors.sequential.RdPu_r)))

#Диаграмма по продажам
fig_sales = go.Figure(go.Pie(labels=top_auto['бренд'], values=top_auto['продажа_usd'],
                             textinfo='label+percent', marker=dict(colors=px.colors.sequential.RdPu_r)))

#Сетка для размещения диаграмм рядом
fig = make_subplots(rows=1, cols=2, subplot_titles=['Доля по количеству', 'Доля по сумме продаж'],
                    specs=[[{'type': 'domain'}, {'type': 'domain'}]])

#Добавление диаграмм на сетку
fig.add_trace(fig_quantity.data[0], 1, 1)
fig.add_trace(fig_sales.data[0], 1, 2)

#Регулировка размера графика и центрование заголовка
fig.update_layout(showlegend=True, title_text="Доли продаж по брендам", height=600, width=1200, title_x=0.5)
fig.show()

Фольксваген - он же "народный автомобиль" лидирует и в количестве проданных авто (546 штук), и в сумме продаж (10 182 272 usd) за весь период. Доля продаж по количеству Ауди и Порше всего по 8% каждый (а это по 52 автомобиля продано у каждого бренда), однако доля по сумме продаж у Порше 26.4%, а у Ауди 21%, суммарно чуть меньше половины общего объема, в то время как Фольксваген с огромным перевесом в количестве проданных авто составляет лишь 52.6%.

Это объясняется тем что Порше и Ауди - люксовые автомобили, их стоимость существенно выше чем у моделей Фольксвагена которые выпускаются на широкую аудиторию потребителя. Отсюда такая разница в количестве проданных автомобилей, и разнице в стоимости.

Продажи авто по месяцам¶

In [81]:
#Сводная таблица с месяцами и марками
month_auto = mer_auto.groupby(['месяц', 'бренд'])['количество'].sum().reset_index()

#Месяца человековыми буквами
month_auto['месяц'] = month_auto['месяц'].replace({'01': 'Январь', '02': 'Февраль', '03': 'Март', '04': 'Апрель',
                                            '05': 'Май', '06': 'Июнь', '07': 'Июль', '08': 'Август', '09': 'Сентябрь'})

month_auto
Out[81]:
месяц бренд количество
0 Январь Audi 2
1 Январь Porsche 1
2 Январь Volkswagen 162
3 Февраль Audi 2
4 Февраль Porsche 5
5 Февраль Volkswagen 119
6 Март Audi 9
7 Март Porsche 7
8 Март Volkswagen 62
9 Апрель Audi 5
10 Апрель Porsche 8
11 Апрель Volkswagen 65
12 Май Audi 7
13 Май Porsche 8
14 Май Volkswagen 138
15 Июнь Audi 4
16 Июнь Porsche 5
17 Июль Audi 10
18 Июль Porsche 7
19 Август Audi 7
20 Август Porsche 7
21 Сентябрь Audi 6
22 Сентябрь Porsche 4
In [82]:
#График с продажей авто по месяцам
fig = px.bar(month_auto, x='месяц', y='количество', color='бренд', text = 'количество',
             color_discrete_sequence=px.colors.qualitative.Prism[2:],
             barmode='group', height=550)

fig.update_traces(textposition='outside') #Чтобы количество отображалось над столбцами

#Названия графика
fig.update_layout(title='Продажа автомобилей по месяцам',
                 xaxis_title='Месяц',
                 yaxis_title='Количество проданных')

fig.show()

Что ж, открылась картина того почему с января по май хорошо держались продажи, в мае произошел скачок и дальше случился резкий спад выручки. Фольксвагены перестали продаваться :) Как нам известно, они составляли большую часть выручки, и попытка выйти на премиум-сегмент отказавшись от более доступных автомобилей судя по графикам оказалось не лучшей идеей.

Общие продажи по регионам¶

In [83]:
#Сводная таблица с количеством продаж по регионам
mer_region = mer_auto.groupby('регион')['количество'].sum().reset_index()
mer_region = mer_region.sort_values(by='количество', ascending=False)

mer_region
Out[83]:
регион количество
0 Алматы 484
4 Нур-Султан 59
1 Атырау 43
3 Костанай 26
2 Караганда 23
5 Уральск 15
In [84]:
#Визуализирую регионы с продажами
fig = px.bar(mer_region, x='количество', y='регион', color='регион', text ='количество',
            color_discrete_sequence=px.colors.qualitative.Prism[4:])

fig.update_layout(title='Общее количество продаж по регионам',
                 xaxis_title='Количество продаж',
                 yaxis_title='Названия регионов')
fig.show()

Больше всего продаж в регионе Алматы (484), он лидирует с большим отрывом от остальных что не удивительно, ведь Алматы самый крупный по численности населения город в Казахстане. Теперь нужно посмотреть какие машины продаются лучше по регионам.

Продажи по регионам и брендам¶

In [85]:
#Сводная таблица с регионами и продаваемыми там брендами
mer_region_auto = mer_auto.groupby(['регион', 'бренд'])['количество'].sum().reset_index()
mer_region_auto
Out[85]:
регион бренд количество
0 Алматы Audi 43
1 Алматы Porsche 51
2 Алматы Volkswagen 390
3 Атырау Volkswagen 43
4 Караганда Volkswagen 23
5 Костанай Audi 2
6 Костанай Volkswagen 24
7 Нур-Султан Audi 7
8 Нур-Султан Porsche 1
9 Нур-Султан Volkswagen 51
10 Уральск Volkswagen 15

Так как Алматы имеет огромный отрыв в количестве продаж авто - строить единый график с остальными регионами не информативно. Я разделю сводную таблицу на остальные регионы, и отдельно Алматы.

In [86]:
#Только Алматы
only_alm = mer_region_auto.query('регион == "Алматы"')
only_alm = only_alm.sort_values(by='количество', ascending=False)
only_alm
Out[86]:
регион бренд количество
2 Алматы Volkswagen 390
1 Алматы Porsche 51
0 Алматы Audi 43
In [87]:
#График с показателями продаж в Алматы
fig_alm = go.Figure(go.Pie(labels=only_alm['бренд'], values=only_alm['количество'], 
                            textinfo='label+percent+value', 
                            marker=dict(colors=px.colors.sequential.GnBu_r),
                            name="Доля продаж топ-3 компаний"))
                            #insidetextorientation='radial'))

fig_alm.update_layout(showlegend=True, title_text="Продажи в Алматы", height=600, width=1200, title_x=0.5)
fig_alm.show()

Продано 390 Фольксвагенов, 51 Порш, и 43 Ауди. Алматы превосходит по количеству продаж каждой марки авто все остальные регионы вместе взятые.

In [88]:
#Уберем Алматы
not_alm = mer_region_auto.query('регион != "Алматы"')
not_alm['количество'] = not_alm['количество'].sort_values(ascending=False)
not_alm
Out[88]:
регион бренд количество
3 Атырау Volkswagen 43
4 Караганда Volkswagen 23
5 Костанай Audi 2
6 Костанай Volkswagen 24
7 Нур-Султан Audi 7
8 Нур-Султан Porsche 1
9 Нур-Султан Volkswagen 51
10 Уральск Volkswagen 15
In [89]:
#График с продажами в регионах без Алматы
fig = px.bar(not_alm, x='регион', y='количество', color='бренд',
             title='Продажа автомобилей в остальных регионах',
             labels={'регион':'Регион', 'количество':'Количество проданных'},
             text = 'количество',
             height=550,
             color_discrete_sequence=px.colors.qualitative.Prism[1:])

fig.update_traces(textposition='outside') #Чтобы количество отображалось над столбцами

fig.show()

Опять же, в основном продавались Фольксвагены. За весь период только один раз продан Порш в Нур-Султане, и 9 Ауди, два из которых в Костанае и 7 в Нур-Султане.

Эти графики подтверждают что попытка оставить только премиум сегмент откзавшись от доступных авто для широкой аудитории потребителя повлекло за собой резкое падение продаж. Реализация Фольксвагенов составляла львинную долю продаж в каждом из регионов без исключения.

Выводить дополнительные графики с продажами по месяцам в Атырау и Нур-Султане не имеет смысла, т.к. нам уже известно что Фольксвагены продавались до мая месяца.


Исходя из этой информации есть несколько рекомендаций:

  • Необходимо вернуть в продажу Фольксвагены :) Эти машины пользуются спросом, отказ от них наносит удар по прибыли компании.

  • Рекомендую остатки Порше и Ауди перевезти в Алматы, и сконцентрироваться на продаже премиум сегмента именно там. С такими показателями продаж реализация премиум сегмента будет лучше.

  • В случае отказа от Фольксвагенов держать салоны во всех остальных регионах кроме Алматы не целесообразно. Рекомендую их закрыть, таким образом сократив расходы компании на аренду помещений.

BCG анализ Mercur Auto¶

BCG анализ позволит взглянуть на продаваемые бренды чуть под другим углом. Будет не лишним доказать преимущество Фольксвагенов для прибыли компании, а так же узнать чем на данном этапе являются продажи Ауди и Порше.

In [90]:
#Сводная таблица с продаваемыми брендами,расчетом общего количества и средней цены для каждого бренда
brand_data = mer_auto.groupby('бренд').agg({'количество': 'sum', 'цена_usd': 'mean'}).reset_index()

#Подготовка данных для построения графика
brand_data['количество'] = (brand_data['количество'] - brand_data['количество'].min()) / (brand_data['количество'].max() - brand_data['количество'].min())
brand_data['цена_usd'] = (brand_data['цена_usd'] - brand_data['цена_usd'].min()) / (brand_data['цена_usd'].max() - brand_data['цена_usd'].min())
In [91]:
#Создание BCG-диаграммы
plt.figure(figsize=(9, 8))
plt.scatter(brand_data['количество'], brand_data['цена_usd'], s=700, alpha=0.8, edgecolors='k')

#Добавление квадрантов
plt.axvline(0.5, color='grey', linestyle='-')
plt.axhline(0.5, color='grey', linestyle='-')

#Подписи квадрантов
plt.text(0.25, 0.75, 'Вопросительные знаки', ha='center', va='center', fontsize=14, alpha=0.5)
plt.text(0.75, 0.75, 'Звезды', ha='center', va='center', fontsize=14, alpha=0.5)
plt.text(0.25, 0.25, 'Собаки', ha='center', va='center', fontsize=14, alpha=0.5)
plt.text(0.75, 0.25, 'Дойные коровы', ha='center', va='center', fontsize=14, alpha=0.5)

#Метки брендов
for i, brand in enumerate(brand_data['бренд']):
    plt.annotate(brand, (brand_data['количество'].iloc[i], brand_data['цена_usd'].iloc[i]))

#Добавление сетки
plt.grid(True, linestyle='--', alpha=0.8)

plt.xlabel('Количество (Рыночная доля)')
plt.ylabel('Цена (Рыночный рост)')
plt.title('BCG-анализ Mercur Auto')

plt.show()

Вопросительные знаки - обычно это начальная точка новых товаров. Характерны такие признаки как высокий темп роста продаж, требуют больших инвестиций в поддержку и развитие, низкая прибыль в краткосрочном периоде.

Звезды - лидеры растущего рынка. Имеется высокий темп роста продаж, высокий уровень прибыли, возможен дальнейший рост, но требует значительных инвестиций.

Собаки - убыточный товар. Зачастую возможности по росту продаж ограничены, это может быть новый товар на рынке потерпевший неудачу, или же товар падающего рынка.

Дойные коровы - лидеры стагнирующего рынка. Имеют высокий уровень прибыли, дальнейший рост вряд-ли случится, эта категория питает компании долгосрочной стабильной прибылью.

Выведенный график BCG анализа Mercur Auto показывает что у компании имеются две марки авто (Ауди и Порше) являющихся яркими представителями вопросительных знаков, а так же Фольксвагены в роли дойных коров, являющиеся основой прибыли Mercur Auto.


Исходя из этого анализа выдвигаю следующие рекомендации:

  • Учитывая массовость и прибыльность Фольксвагенов, рекомендую выставить еще одну марку авто - Scoda. Она так же относится к концерну Фольксваген Гроуп, так же производится на широкую аудиторию и имеет доступную стоимость для большинства потребителей. Я полагаю что этот бренд займет нишу "звёзд" и в дальнейшем окажется "дойной коровой" повторив путь Фольксвагена, т.к. тоже имеет потенциал массово продаваться. Конечно же данное внедрение требует дополнительного тщательного анализа рынка для принятия решения.

  • Для развития премиум сегмента следует подготовить хорошую рекламную кампанию. Рекомендую организовать временные скидки, бонусы, подарки или финансовые программы для привлечения внимания покупателей. Обеспечить высокий уровень обслуживания клиентов в салоне и после продажи тем самым показав статус салонов с премиум сегментом авто. В дальнейшем, при благоприятном исходе событий рассмотреть на внедрение в продажу новых брендов премиум класса.

  • Следует всегда учитывать специфику люксовых авто. Продаж закономерно будет меньше относительно доступных автомобилей, но увеличив темп роста продаж инвестициями в развитие данного направления можно добиться ощутимого прироста в прибыли на долгосрочной перспективе.

Выводы и рекомендации¶

Проведена комплексная очистка датасета и восстановление утраченных данных, с попыткой сохранить максимум имеющейся информации. Были удалены лишние столбцы дублирующие информацию, оставшиеся приведены к snake_case стилю для удобства работы с ними, числа приведены к нужным типам данных, неявные дубликаты заменены на корректные значения, восстановлены и сокращены (для оптимзации скорости загрузки датасета) типы привода к единому обозначению, сокращены (для опримизации скорости загрузки датасета) обозначения вида топлива, заполнены пропуски значений с задачей максимально сберечь данные в датасете.

Выводы¶

Общие¶

  • Чаще всего приобретались легковые авто и внедорожники.

  • С большим отрывом лидируют такие бренды как Lada, Tayota, Hyundai. Это можно объяснить широкой доступностью расходников и запчастей на данные марки, привлекательной ценой (в этом плане выигрывает Лада у всех), а у Тайоты и Хёндая высочайший срок службы.

  • GAZ, KAMAZ, UAZ самые популярные авто для коммерции. GAZ пользуется спросом у спецслужб (скорая, полиция), Камазы распространены в строительных организациях и транспортных компаниях, Уазики гибки в использовании, их линейка коммерческого транспорта имеет как авто для перемещения пассажиров, так и грузовые авто до 3.5 тон.

  • Объем продаж к сентябрю 2019го составлял 1322 миллиона долларов, прирост был плавным на протяжении всего периода. Динамика продаж показывает нам тоже относительно плавную картину происходящего, в феврале мы имеем самый низкий показатель, а в июле всплеск продаж выделяющийся на общей картине. Ажиотаж к покупке Tayota Camry мог привести к повышенной активности продаж в июле.

  • Бипэк авто, крупнейший холдинг имеющий самую большую долю авторынка Казахстана (30,8%). Помимо нблюдаем дистрибьютора Tayota motor kazahstan (24,3% рынка) и astana motors (20,7%).

  • Лидеры продаж по регионам Алматы (13558 продаж) и Нур-Султан (9981 продаж). В средних значениях от 3157 до 3741 продаж держатся Костанай, Атырау, и Шымкент.

По Mercur Auto¶

  • Общая выручка за весь период с января по сентябрь 2019го года у компании Mercur Auto составила 19 355 276 usd. Средняя ежемесячная выручка составляет 2 150 586 usd.

  • Фольксваген лидирует и в количестве проданных авто (84%, 546 штук), и в сумме продаж (10 182 272 usd) за весь период. Доля продаж по количеству Ауди и Порше всего по 8% каждый (по 52 автомобиля продано у каждого бренда).

  • Алматы превосходит по количеству продаж каждой марки авто все остальные регионы вместе взятые (484 единиц), в то время как остальные регионы не превышают 60 продаж за имеющийся период. В Алматы продано 390 Фольксвагенов, 51 Порш, и 43 Ауди.

  • Отказ от продаж Фольксагенов значительно нарушил рост прибыли для компании. Попытка оставить только премиум сегмент откзавшись от доступных авто для широкой аудитории потребителя повлекло за собой резкое падение продаж, реализация Фольксвагенов составляла львинную долю продаж в каждом из регионов без исключения.

Рекомендации¶

Для сбора и хранения данных¶

  • Рекомендую ввести индексацию строк присваивая уникальный id для каждой. Это избавит массив данных от множества явных дубликатов, искать информацию станет легче.

  • Рекомендую заблокировать возможность ручного ввода информации о характеристиках автомобиля. Необходимо сделать выпадающее окно с вариантами выбора вида топлива, типа привода, коробки передач. Таким образом мы получим стандарт введения информации в базу данных, что позволит быстро ориентироваться в них и оперативно собирать статистику. Так же это облегчит жизнь аналитикам данных.

  • Рекомендую вести учет информации в единой БД. При объединении данных хранящихся на разных сервисах/облаках неизбежно возникают съехавшие значения, ошибки при выгрузке данных, а так же может быть утеряна часть этих данных. Это позволит иметь быстрый доступ к архивам без надобности склеивать данные, убережет их от возникновения части ошибок при выгрузке.

  • Рекомендую переименовать в БД поля латинскими символами. Это так же стандартизирует вид базы, упростив работу с данными аналитикам/инженерам данных.

Для Mercur Auto¶

  • Необходимо вернуть в продажу Фольксвагены. Эти машины пользуются спросом, отказ от них наносит удар по прибыли компании.

  • Рекомендую остатки Порше и Ауди перевезти в Алматы, и сконцентрироваться на продаже премиум сегмента именно там. С такими показателями продаж реализация премиум сегмента будет лучше.

  • Учитывая массовость и прибыльность Фольксвагенов, рекомендую выставить еще одну марку авто - Scoda. Она так же относится к концерну Фольксваген Гроуп, так же производится на широкую аудиторию и имеет доступную стоимость для большинства потребителей. Я полагаю что этот бренд займет нишу "звёзд" и в дальнейшем окажется "дойной коровой" повторив путь Фольксвагена, т.к. тоже имеет потенциал массово продаваться. Конечно же данное внедрение требует дополнительного тщательного анализа рынка для принятия решения.

  • Для развития премиум сегмента следует подготовить хорошую рекламную кампанию. Рекомендую организовать временные скидки, бонусы, подарки или финансовые программы для привлечения внимания покупателей. Обеспечить высокий уровень обслуживания клиентов в салоне и после продажи тем самым показав статус салонов с премиум сегментом авто. В дальнейшем, при благоприятном исходе событий рассмотреть на внедрение в продажу новых брендов премиум класса.

  • Следует всегда учитывать специфику люксовых авто. Продаж закономерно будет меньше относительно доступных автомобилей, но увеличив темп роста продаж инвестициями в развитие данного направления можно добиться ощутимого прироста в прибыли на долгосрочной перспективе.

  • В случае отказа от Фольксвагенов держать салоны во всех остальных регионах кроме Алматы не целесообразно. Рекомендую их закрыть, таким образом сократив расходы компании на аренду помещений.